Skip to content

Regular Expression Denial of Service (ReDoS)

Overview

Implementations MUST avoid regular expressions vulnerable to catastrophic backtracking.

The Problem

Certain regex patterns exhibit exponential time complexity on specific inputs:

regex
# Vulnerable pattern
(a+)+$

# Attack string: "aaaaaaaaaaaaaaaaaaaaaaaaaaaa!"
# Time: O(2^n) where n = number of 'a's

Vulnerable Patterns

Nested Quantifiers

regex
# Bad
(a+)+
(a*)*
(a+)*
(.*)+

# Good
a+
a*

Overlapping Alternations

regex
# Bad
(a|a)+
(ab|a)+b

# Good
a+
a+b?

Patterns in Beancount Context

Use CaseVulnerableSafe Alternative
Account match(:[A-Za-z]+)+(:[A-Za-z]+)* with length limit
Currency[A-Z]+[A-Z]{1,24}
Number[0-9,]+[0-9]{1,50}(,[0-9]{3})*

Requirements

Implementations MUST:

  1. Audit all regex patterns for ReDoS vulnerability
  2. Use non-backtracking engines when available (RE2, rust regex)
  3. Set match timeouts if using backtracking engines
  4. Limit input length before regex matching

Safe Regex Engines

EngineBacktrackingReDoS Safe
RE2 (Google)NoYes
Rust regexNoYes
HyperscanNoYes
PCREYesNo
Python reYesNo
JavaScriptYesNo

Mitigation Strategies

1. Use Linear-Time Engines

rust
// Rust: regex crate is safe by design
use regex::Regex;
let re = Regex::new(r"pattern").unwrap();  // guaranteed O(n)

2. Set Timeouts

python
# Python: use regex with timeout
import regex
regex.match(pattern, string, timeout=1.0)

3. Limit Input Length

python
# Check length before matching
if len(input) > MAX_LENGTH:
    raise ValueError("Input too long")
result = re.match(pattern, input)

4. Avoid Regex for Simple Parsing

python
# Bad: regex for fixed format
date = re.match(r"(\d{4})-(\d{2})-(\d{2})", line)

# Good: direct parsing
year, month, day = line[:4], line[5:7], line[8:10]

Testing

Test with attack strings:

python
attack_strings = [
    "a" * 30 + "!",           # Nested quantifier attack
    "a" * 30 + "b" * 30,      # Overlapping alternation
    " " * 1000 + "x",         # Leading whitespace
]

Verify each completes in < 100ms.

References