TL;DR
ReDoS (Regular Expression Denial of Service) happens when a regex pattern takes exponentially longer to process certain inputs. Attackers send crafted strings that cause your regex to run for minutes or hours, freezing your Node.js event loop. Avoid nested quantifiers and test your regexes with tools like safe-regex.
How ReDoS Works
Some regex patterns have "catastrophic backtracking" where the engine tries many different ways to match before failing. Each additional character can double the processing time.
// Evil pattern: nested quantifiers
const emailRegex = /^([a-zA-Z0-9]+)+@/;
// Normal input: "user@example.com" - fast
// Attack input: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!" - SLOW!
// The regex tries every way to split the "a"s
// 30 characters = 2^30 combinations = ~1 billion tries
Node.js warning: JavaScript runs on a single thread. While the regex is processing, nothing else can execute. One ReDoS attack can freeze your entire server.
Dangerous Patterns
- Nested quantifiers:
(a+)+,(a*)*,(a+)* - Overlapping alternations:
(a|a)+ - Groups with repetition:
([a-zA-Z]+)*
How to Prevent ReDoS
// Use atomic groups or possessive quantifiers (if supported)
// Or rewrite the pattern
// Dangerous
const bad = /^([a-zA-Z0-9]+)+$/;
// Safe alternative
const good = /^[a-zA-Z0-9]+$/;
// Or use a library
import validator from 'validator';
validator.isEmail(input); // Pre-tested, safe patterns
How do I test my regexes?
Use tools like safe-regex, rxxr2, or regex-static-analysis. Also test manually with strings like "aaaaaaaaaaaaaaaaaaaaa!" to see if they hang.
Should I avoid regex entirely?
No, but be careful with user-controlled input. Use battle-tested libraries for common patterns (emails, URLs) and limit input length before regex processing.