Vulnerability

Regex Denial of Service (ReDoS)
detect, understand, remediate

Regex denial of service (CWE-1333) abuses catastrophic backtracking in poorly written regular expressions. A single crafted string of a few hundred characters can pin a CPU core for minutes, freezing request handlers, exhausting worker pools, and taking the application offline without any traffic flood.

No credit card required. Free plan available forever.

Severity

High

CWE ID

CWE-1333

OWASP Top 10

A05:2021 – Security Misconfiguration

CVSS 3.1 Score

7.5

What is regex denial of service?

Regex denial of service (ReDoS), tracked as CWE-1333, is an availability vulnerability that abuses the worst case behaviour of a backtracking regular expression engine. Most production languages (JavaScript, Java, Python, Ruby, C#, PHP) ship with regex engines that walk every possible match path when a pattern fails to match. With a carefully crafted input, the number of paths can grow exponentially with the length of the input string. A pattern that runs in microseconds against benign input can take minutes against a 100 character payload.

The attack model is simple. The attacker locates any user controlled value that is fed into a vulnerable regular expression. That can be a query parameter, a JSON field, an uploaded filename, an HTTP header, or a parsed log line. They submit a payload designed to cause catastrophic backtracking. While the regex engine grinds through paths, the request handler holds a CPU core, a worker thread, or an event loop tick. A handful of parallel requests can saturate the entire process, blocking legitimate traffic. This makes ReDoS a true asymmetric attack, similar in shape to denial of service at the network layer but launched with kilobytes of input.

ReDoS is most often introduced by reusing patterns from forums, copying validation regex from older libraries, or generating regex from user input without validation. It is also a common source of CVEs in popular packages, which is why it should be treated as a routine concern of any vulnerable dependency review. Single threaded runtimes such as Node.js are especially exposed because a stuck regex blocks every request the process is handling, not just the malicious one.

How it works

1

Locate a vulnerable pattern

The attacker finds a regex with overlapping or nested quantifiers, ambiguous alternation, or repeated groups. Common shapes include (a+)+, (a|a)+, (.*)*, and ([a-zA-Z]+)*. These create many ways to match the same characters.

2

Find the input surface

Any user controlled string that reaches the pattern qualifies. This includes form fields with format validation, search filters, URL parsers, user agent parsers, log shippers, email validators, and route matchers in middleware.

3

Craft a backtracking payload

The attacker sends a string that is almost a match, with a final character that forces the engine to fail and retry. A typical shape is many repeats of the matching token followed by one non-matching character, which triggers exponential path exploration.

4

Pin the worker

The regex engine consumes a CPU core for seconds or minutes. Concurrent requests pile up, queues fill, and health checks fail. With enough parallel attackers, the process restarts under load and the cycle repeats.

Examples of vulnerable patterns

These shapes are sometimes called evil regex. The common feature is that the engine has more than one way to match the same characters, so failing input forces it to try every combination before giving up.

Nested quantifiers

(a+)+$

The inner quantifier and the outer quantifier both consume the same characters. When the trailing anchor fails, the engine tries every partition of the input between the two quantifiers.

Ambiguous alternation

(a|aa)+$

Both alternatives match the same letter. Each step the engine has two choices, and a failing tail forces it to walk every combination.

Greedy plus inside greedy star

(.*a){25}

A greedy star is followed by another quantified group that re-scans the same characters. Long inputs without a trailing match explode in time.

Email validators with grouped repetition

^([a-zA-Z0-9])(([\.\-]?[a-zA-Z0-9]+)*)@

Validators copied from old guides often have groups that overlap on dots or dashes. Crafted local parts trigger backtracking before the at sign is reached.

Common causes

Validators copied from forums

Email, URL, and password validators are routinely copied from blogs and answer threads without checking how they behave on adversarial input. Many widely shared patterns include overlapping groups.

Vulnerable dependencies

Routing libraries, log parsers, header parsers, and serialisation packages have all shipped CVEs for ReDoS. A pinned version that looked safe at install time can become a known vulnerability after disclosure.

Backtracking engines on user input

Default regex engines in JavaScript, Java, Python, Ruby, C#, and PHP backtrack. When user input flows directly into a complex pattern with no time budget, the worst case is unbounded.

Regex generated from user input

Search features that build a regex from user input, or rule editors that allow operators to author patterns, can introduce evil regex on demand. Without validation, the application owns the worst case of every pattern it compiles.

How to detect it

Automated detection

  • SecPortal's code scanner runs SAST rules against your repositories that flag nested quantifiers, ambiguous alternation, and other known evil regex shapes
  • SCA dependency auditing surfaces packages with disclosed ReDoS CVEs in your lockfiles and pins findings to the affected version range
  • Findings are auto scored with a CVSS vector that reflects availability impact, then routed to remediation owners through findings management

Manual testing

  • Profile every regex used on user controlled input with adversarial strings of growing length and measure CPU time per request
  • Use a static analyser for evil regex such as the ESLint plugin for security rules, regexploit, or the OWASP Validation Regex Repository review notes
  • During a pentest, fuzz fields with strings shaped like aaaa...aaa! and watch for response times that grow superlinearly with input length

How to fix it

Switch to a non backtracking engine where you can

Engines based on automata (RE2 in Go, the re2 bindings for Python, Node, and Java) run in time linear in the size of the input and never backtrack. For pure pattern matching, this is the cleanest fix because it removes the entire class of attack.

Refactor patterns to avoid overlap

Rewrite quantified groups so the engine has only one way to match each character. Use possessive quantifiers or atomic groups in engines that support them, and replace ambiguous alternation with explicit character classes.

Cap input length and execution time

Validate input length before compiling or applying a regex. In runtimes that support it (.NET, Java, Go), set an explicit timeout on the match. Treat the timeout as a logged failure, not a silent skip.

Pin and patch dependencies that parse user input

Track ReDoS CVEs in routing, logging, parsing, and serialisation libraries. Apply patched versions and add the original finding to your remediation tracking workflow with a verified close.

Avoid regex for what is not a regex problem

Email, URL, and structured value parsing are better handled by purpose built parsers. A spec compliant parser is faster and safer than the regex it replaces, and removes the patterns most likely to be ReDoS targets.

Reporting a ReDoS finding

Score on availability impact

ReDoS rarely affects confidentiality or integrity. The CVSS vector typically reads C:N/I:N/A:H. Where the regex sits behind authentication, lower the attack vector to AV:A and revisit privileges required.

Capture proof on a non production target

Demonstrate the vulnerability in a staging environment with a single payload and a wall clock timing. Avoid running ReDoS payloads against production. Record the request, the regex, and the file path.

Recommend a defence in depth fix

In the report, propose the engine swap or pattern refactor, plus an input length cap and a match timeout. Two complementary controls keep the finding from regressing if the pattern is touched again.

Compliance impact

Catch evil regex before it ships

SecPortal runs SAST against your repositories and audits dependencies for known ReDoS CVEs. Connect a repo and start scanning for free.

No credit card required. Free plan available forever.