Master

Patterns and strangers

A pattern built from text someone typed is code that runs on their input. Two mistakes here are attacks, not bugs, so both get named.

What you will see

True

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Check the safety rules.

1

Literal matched.

import re lit = re.escape("a.*b") print(bool(re.search(lit, "a.*b")))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
True
2

Wildcard leak.

import re print(len(re.findall("a.b", "axb")))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
1
3

Length capped.

limit = 200 print(len("abcdefgh") < limit)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
True
4

Pattern compiled.

import re pat = re.compile("\d+") print(bool(pat.search("9")))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
True

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Stranger text is escaped at the boundary and length capped before matching, so the pattern and the work are both bounded.
1 take their text
↓
2 escape it
↓
3 cap the length
↓
4 run the bounded match
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

import re sets nothing on screen
lit = re.escape("a.*b") sets nothing on screen
print(bool(re.search(lit, "a.*b"))) True
Why this works
Their text is data

Input becomes a pattern only by accident. Escaping at the boundary makes every character mean itself, which is the rule.

Work is not free

Their length decides the engine work. A cap before matching turns an unbounded cost into a fixed one.

Examples

Escape their text

import re
lit = re.escape("a.*b")
print(bool(re.search(lit, "a.*b")))

Their characters become literals. Unescaped, the dot and star become rules.

A wildcard leak

import re
print(len(re.findall("a.b", "axb")))

An unescaped dot in their input matched a character they did not type.

Cost from their side

import re
text = "a" * 8
print(bool(re.match("(a+)+b", text)))

Their text length decides the work. A cap on length caps the work.

Timeout or cap

limit = 200
print(len("abcdefgh") < limit)

Refuse long input before matching. A refusal is cheaper than a timeout.

No eval of a pattern

import re
pat = re.compile("\d+")
print(bool(pat.search("9")))

A pattern is data for the engine, never code. Compile it, do not run it.

Report without echoing

import sys
print("rule rejected", file=sys.stderr)

Say which rule failed, not the whole input. Echoing back stranger text invites noise.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← How the engine walks
Previous Lesson
How the engine walks
Next Lesson
Building a pattern
Building a pattern →