Regex tester · Guide
Regex Backtracking Tester: Finding Catastrophic Patterns
Most regex engines backtrack: when a path fails they rewind and try another. Usually that costs microseconds. With the wrong pattern shape it costs exponential time, and a 30-character input can pin a CPU core for years.
The shape to look for
The danger sign is a quantifier applied to a group that itself contains a quantifier, where the inner parts can match the same text — nested quantifiers with ambiguity:
(a+)+$ # classic — exponential on "aaaaaaaaaaaaaaaaaaaaX"
(\s*\w+)*$ # same shape, looks harmless
(\d+|\w+)+$ # alternation that can match the same text
^(\w+\s?)*$ # very common in "validate a name" patternsOn failure the engine must try every way of splitting the input between the inner and outer quantifiers. That count doubles with each added character.
Why it only fails sometimes
A matching input returns quickly, because the engine stops at the first success. The explosion happens on inputs that almost match and then fail at the end — which is why these patterns pass tests and die in production.
To test one, feed it a long repetition of the character it accepts plus one character it cannot: "a" * 30 + "X". If the tester hangs, the pattern is unsafe for untrusted input.
Fixing it
Remove the ambiguity so only one split is possible. A negated character class is usually both faster and clearer than a lazy quantifier:
(a+)+$ -> a+$
".*?" -> "[^"]*"
^(\w+\s?)*$ -> ^\w+(?:\s\w+)*$Where the engine supports them, atomic groups (?>...) and possessive quantifiers a++ forbid backtracking into a section entirely — available in Java, PCRE and .NET, not in JavaScript or Python.
Engine-level protection
.NET accepts a timeout on the Regex constructor, which converts a hang into a catchable exception. Go and Rust use RE2-style engines with no backtracking at all, so they are immune by construction — at the cost of no lookarounds or backreferences.
JavaScript, Python, Java, PHP and Ruby all backtrack with no built-in limit. If a pattern in those languages touches user input, review its shape, and never build a regex from user-supplied text.
Frequently asked questions
How do I know if a pattern is vulnerable?
Look for a quantified group containing another quantifier where both can match the same characters, then test with a long almost-matching string.
Does a lazy quantifier fix backtracking?
No. Lazy changes the order of attempts, not their number. Remove the ambiguity instead.
Which languages are immune?
Go and Rust use RE2-style linear engines. Most others backtrack without limit.
Ready to try it?
Open the free browser-based Regex tester and apply what you just read — no sign-up, runs locally.
Open the Regex tester tool