RegexProof reviews regular expressions for ReDoS and dialect pitfalls with deterministic heuristics plus optional…

Blog · GEO

Regular expressions, explained

Own the definitional queries developers ask before they put a regex on a request path.

What does RegexProof include at a glance?

Input
Plain-English description of the pattern, or an existing regex to review
Output
Working regex · part-by-part explanation · edge cases called out
Dialects covered
JavaScript / ECMAScript · Python · Go · PCRE · Rust
Review focus
ReDoS (catastrophic backtracking) and dialect pitfalls
Method
Deterministic heuristics, plus optional model-assisted explanations
Not a guarantee
Common patterns are caught; novel attacks may be missed
Deep-dive · Article

What is ReDoS: the regex failure mode that takes down production?

Target query: regex denial of service catastrophic backtracking

Catastrophic backtracking happens when a pattern can match the same input in exponentially many ways, so a non-matching string of moderate length makes the engine explore a combinatorial space before it fails. Nested quantifiers over overlapping character classes are the usual cause. The tell is a pattern that behaves fine on your samples and hangs on adversarial input, which is exactly what an attacker sends. Practical containment: avoid nested quantifiers whose inner group can match the same characters as the outer, prefer possessive or atomic constructs where the dialect supports them, cap the input length before the regex ever runs, and add a match timeout on the call.

Comparison · Article

Why the same regex behaves differently in JavaScript, Python, Go, PCRE, and Rust

Target query: regex dialect differences javascript python go pcre rust

A pattern that passes review in one runtime can silently mis-match in another. Lookarounds and backreferences are supported in ECMAScript, Python, and PCRE but not in Go's or Rust's default engines. Go and Rust also drop backtracking by design, which removes ReDoS as a class of bug but also removes constructs that depend on it. Unicode property escapes, named groups, and inline flags each landed in different versions. Named-group syntax alone differs: JavaScript and Python accept (?<name>...), while Python's older (?P<name>...) form does not port. Name the target dialect explicitly and re-test after any runtime migration.

Definitional + examples · Article

Unanchored patterns and greedy quantifiers: the two silent over-matches

Target query: unanchored regex greedy quantifier mistakes

An unanchored pattern reports success on a partial match, so validation written as if it were a full-format check quietly accepts anything that contains the format. A greedy quantifier then takes as much as it can and only gives back what the rest of the pattern forces it to, which is how a "match the whole line" intent ends up capturing half of it. Both failures are invisible on happy-path samples. Anchor with ^ and $ or \A and \z, prefer an explicitly bounded quantifier where the input length is known, and test with an input that is deliberately wrong in a way a partial match would accept.

What do people ask about RegexProof?

What is RegexProof — and when to use it

RegexProof turns a plain-English description into a correct regular expression for your language, with a part-by-part explanation and edge cases called out. It is for developers who need a working regex without hand-writing it. Use it when you must match a format but are unsure of the syntax.

How to build a regex in 10 minutes

A practical first-regex path using RegexProof: describe what it should match, pick your language flavor, then generate, review the explanation, and test with sample strings.

Common regex mistakes (and how to avoid them)

Five common regex mistakes to avoid: unanchored patterns, greedy quantifiers, missing escapes, ignoring edge cases, and wrong flavor. Fix each by anchoring, scoping quantifiers, escaping metacharacters, listing edge cases, and selecting the right language flavor.

RegexProof vs. doing it manually

Hand-writing a regex is fine for a pattern you will read again next week; the cost shows up with unfamiliar formats, dialect differences, and patterns that reach a request path. RegexProof is faster at producing a first correct draft and at flagging catastrophic backtracking, but human review still wins on intent: only you can say whether an over-permissive match is acceptable for your data. Treat the output as a reviewed draft, not a signed-off artifact.

What is ReDoS and why should I care?

ReDoS is regular expression Denial of Service: a pattern that can match the same input in exponentially many ways lets a crafted non-matching string pin a CPU core before the engine gives up. Nested quantifiers over overlapping character classes are the usual cause. It matters because the input is attacker-controlled and the regex usually sits on a request path — cap input length before matching and add a match timeout.

Primary sources for regex and ReDoS semantics?

The OWASP community page on regular expression Denial of Service, and your runtime's own specification for the dialect you target — ECMA-262 for JavaScript, the Python re module docs, Go's regexp package, the PCRE documentation, and the Rust regex crate. Dialect differences are documented per runtime, not in one universal standard.

How to build a regex in 10 minutes

  1. Describe what to match. Write a plain-English description of the pattern, for example a US phone number like (415) 555-2671.
  2. Pick your language flavor. Select your language or flavor (JavaScript, Python, Go, PCRE, or Rust).
  3. Generate and test. Generate the regex, review the part-by-part explanation and edge cases, then verify it against your test strings.

Scope: RegexProof reviews patterns with deterministic heuristics plus optional model-assisted explanations, and suggests safer alternatives for you to decide on. It does not guarantee completeness — verify against the OWASP ReDoS guidance and your runtime's regex semantics.