C.W.K.
Stream
Lesson 08 of 12 · published

ReDoS — Regex DoS Attack

~10 min · redos, security, attack

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

The attack vector

ReDoS (Regular Expression Denial of Service) is the practical exploitation of catastrophic backtracking. An attacker who can supply input to a vulnerable regex causes the server to spin a CPU core for minutes — or until your process is killed by an out-of-memory or timeout signal.

Real-world example: Cloudflare 2019

In July 2019, a single regex with nested quantifiers caused a global Cloudflare outage. The pattern was checking firewall rules against HTTP request bodies. An adversarial body triggered exponential backtracking; CPU saturation propagated through the network. Outage lasted ~30 minutes, affected millions.

Common vulnerable patterns in the wild

  • Email validators with nested quantifiers — many old email regexes have (.+)+ shapes.
  • URL parsers with greedy lookahead.*?(?=&) can backtrack badly on long inputs without &.
  • HTML/XML extraction<(.+)>.*</\1> with backreferences and greedy.
  • Markdown rewrite**(.+?)** chains can explode if patterns nest weirdly.

Defense

  1. Don't run untrusted patterns. If users can write regex (search filters, etc.), use RE2 or impose strict timeouts.
  2. Don't feed untrusted input to fragile patterns. Use atomic groups, possessive quantifiers, negated classes.
  3. Set timeouts. Most languages let you cap regex execution time. Python's re doesn't natively, but regex module does.
  4. Use RE2 for any user-supplied input — Go's regexp, Python's google-re2 binding. Linear time guaranteed.

Detection tools

Tools exist to scan codebases for vulnerable patterns: safe-regex (npm), recheck, GitHub's CodeQL queries. Run periodically.

Code

ReDoS-safe alternatives·python
# Vulnerable: greedy quantifiers in alternation
# (a|aa|aaa)+b   — explodes on 'a'*30+'X'

# Safe rewrite: deduplicate alternatives, use atomic group
# (?>a+)b   — fails fast

# Vulnerable: nested groups with overlapping quantifiers
# (.+)+@   — email-like, explodes on long input without @

# Safe: anchor + negated class
# ^[^@]+@   — linear time, same matching power for emails

# Vulnerable: lazy quantifier with no boundary
# .+?(?=END)   — explodes if END never appears

# Safe: negated class
# [^E]*END   — won't explode

# For untrusted input, use Google's RE2 binding
# pip install google-re2
# import re2
# re2.compile(r'pattern').search(input)  # guaranteed linear

External links

Exercise

Take three regex patterns from your codebase that process user input. For each, ask: 'If a user could control this input, could they make me hang?' If yes, rewrite. If no, document why.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.