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.
1take their text
↓
2escape it
↓
3cap the length
↓
4run 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 resets nothing on screen
lit = re.escape("a.*b")sets nothing on screen
print(bool(re.search(lit, "a.*b")))True
Why this worksTheir 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" * 8print(bool(re.match("(a+)+b", text)))
Their text length decides the work. A cap on length caps the work.
Timeout or cap
limit = 200print(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.