Look for a group that repeats and contains either another repetition or an alternation with overlapping options. Patterns like that can make a backtracking regex engine take exponential time on crafted input, which hangs a request or a whole process. This is called ReDoS.
Why it happens
OWASP describes ReDoS as a denial of service attack that exploits regex engines slowing down sharply on certain inputs. Many engines use backtracking, trying every possible path before concluding a non-matching input fails, and the work can grow exponentially with input length.
OWASP calls a pattern evil if it can get stuck on crafted input. The warning signs are grouping with repetition, and inside that group either another repetition or alternation with overlapping options.
Examples from OWASP
Nested repetition:
(a+)+$
([a-zA-Z]+)*$
Overlapping alternation:
(a|aa)+$
(a|a?)+$
A typical trigger is a long run of the letter a followed by a character that breaks the match, such as an exclamation mark. OWASP gives a scale: a 16 character input of a followed by a non-matching character yields about 65,536 paths, and each extra character roughly doubles the work.
What to look for in a diff
- Find new or changed regular expressions, especially in validation of email addresses, URLs, versions and filenames.
- Look for nested quantifiers: a star or plus after a group that itself contains a star or plus.
- Look for alternations where branches can match the same text.
- Check who controls the input and its length. A regex over a short fixed field is less risky than one over a request body.
- Check whether the pattern is built from user input. OWASP lists regex injection as a case: a user supplied pattern can hang the program.
// red flag: nested repetition on user input
const looksValid = /^([a-zA-Z0-9]+)*$/.test(input);
// simpler and linear: no group repeating a repeat
const looksValid = /^[a-zA-Z0-9]*$/.test(input);
Ways to fix
Rewrite the pattern so no repeated group contains a repeat. Put a length limit on the input before matching. Prefer a parser or a library function over a complex regex for formats like emails and URLs. Some regex engines avoid backtracking by design, so check which one your language uses and whether a linear time option exists. Add a test that feeds a long, nearly matching input and asserts it returns quickly.
It can sit in your dependencies too
OWASP notes open source examples, including a CVE in the minimatch JavaScript library (CVE-2022-3517). A vulnerable pattern inside a dependency is found by dependency scanning, not by reading your own diff, so keep both running.
Try it yourself
Run the code scan demo and read how a finding names the file and line. A reviewer can use the same habit on regex.
Click through it at your own pace, or open it full screen.
Where Safeguard fits
Safeguard offers dependency scanning with reachability analysis, so you can see whether a vulnerable library function is called. Try the free scan at gold.safeguard.sh/scan.
Quick check
Is every nested group a ReDoS risk?
No. The risk comes from a repeated group that contains another repeat or an overlapping alternation, on input an attacker controls.
Can client side validation reveal the problem?
Yes. OWASP notes an evil regex in client code may signal the same vulnerable regex exists on the server.
Sources
Last reviewed: 19 October 2026.