ReDoS (Regex Denial of Service)
debt(d7/e3/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). Tools like semgrep and rexploiter from detection_hints can catch some patterns, but catastrophic backtracking often only shows up under adversarial testing — not a default linter check.
Closest to 'simple parameterised fix' (e3). Per quick_fix, the remediation is rewriting the regex pattern or setting pcre.backtrack_limit / switching to filter_var() — a localised pattern swap, not a one-liner since you typically need to redesign the regex.
Closest to 'localised tax' (b3). applies_to web/api contexts; each vulnerable regex is a local issue at its call site, not an architectural commitment, though regexes scattered across input validation can add up.
Closest to 'serious trap' (t7). The misconception states even well-intentioned regexes with nested quantifiers exhibit exponential backtracking — developers expect regex matching time to scale linearly with input, but it can be exponential, contradicting normal mental models.
Also Known As
TL;DR
Explanation
ReDoS exploits the backtracking behaviour of NFA-based regex engines. Certain patterns — particularly those with nested quantifiers like (a+)+ — require exponential time to determine a non-match for specially constructed inputs. An attacker who can influence the string being matched against such a pattern can cause the thread to spin indefinitely, effectively creating a denial-of-service condition with minimal effort. Mitigations include using atomic groups, possessive quantifiers, or regex analysers to detect vulnerable patterns before deployment.
Common Misconception
Why It Matters
Common Mistakes
- Using nested quantifiers like (a+)+ or alternation that causes exponential backtracking.
- Applying complex user-supplied or application-defined regexes to unbounded user input without length limits.
- Not setting a pcre.backtrack_limit in php.ini or using preg_match() without a timeout.
- Validating email or URL formats with excessively complex regexes — use filter_var() instead.
Code Examples
preg_match('/^(a+)+$/', $userInput);
// Use non-backtracking / atomic: preg_match('/^(?>a+)+$/', $userInput); // or set pcre.backtrack_limit