Safeguard
Industry Analysis

ReDoS: Regular Expression Denial of Service Attacks

ReDoS took down Cloudflare's global network for 27 minutes in 2019 and Stack Overflow in 2016. Here's how one bad regex causes an outage, and how to catch it first.

Aman Khan
AppSec Engineer
8 min read

On July 2, 2019, Cloudflare's global network went dark for 27 minutes. The cause wasn't a DDoS attack or a hardware failure — it was a single regular expression. A WAF rule update shipped a pattern that, against a specific input, forced the regex engine into catastrophic backtracking, pinning CPU cores at 100% across Cloudflare's entire edge network. This is ReDoS: Regular Expression Denial of Service, a vulnerability class where an attacker crafts input that makes a regex engine take exponential — rather than linear — time to evaluate. It doesn't require memory corruption, authentication bypass, or clever exploit chains. It requires one bad pattern, tracked as CWE-1333, sitting quietly in application code, a dependency, or a WAF rule until someone feeds it the wrong string. This post breaks down how ReDoS works, the incidents that prove it's not theoretical, and how to catch it before production does.

What Is ReDoS and Why Can One Regex Take Down a Server?

ReDoS happens when a regular expression's matching engine exhibits exponential or polynomial time complexity on certain inputs, letting an attacker submit a short string that consumes minutes or hours of CPU time. Most regex engines used in JavaScript, Python, Java, and Ruby (NFA-based backtracking engines) try every possible way to match a pattern before failing. Patterns with nested quantifiers — classics like (a+)+, (a|aa)+, or (a|a?)+ — create ambiguity: multiple internal paths can match the same substring, and when the overall match ultimately fails, the engine backtracks through all of them. For a 30-character string, that can mean over a billion evaluation steps. A request that would normally resolve in microseconds instead pegs a CPU core indefinitely, and because most web servers handle requests with limited worker threads or processes, a handful of these requests is enough to exhaust capacity and take a service offline — no botnet required.

How Did a Bad Regex Take Down Cloudflare's Entire Network?

It took down Cloudflare because the vulnerable regex ran inside the WAF's Lua-based rule engine, which processed every single HTTP request across every customer on the network. On July 2, 2019, Cloudflare deployed a new WAF rule containing a regex meant to detect malicious JavaScript. The pattern's structure caused catastrophic backtracking on certain request bodies, and because it executed inline on the request-processing path for all traffic, CPU utilization across Cloudflare's global fleet spiked to 100% almost immediately. The outage lasted 27 minutes and affected customers worldwide before engineers identified the rule and rolled it back. Cloudflare's own postmortem cited this as one of the worst outages in the company's history — not because of scale of intent, but because a single line of regex had a blast radius equal to the entire edge network. It remains the canonical example of why ReDoS is a systemic risk, not just an app-level bug.

Is Cloudflare an Isolated Case, or Has This Happened Before?

It's not isolated — Stack Overflow suffered a nearly identical failure three years earlier. On July 20, 2016, Stack Overflow went down for 34 minutes after a regex used to trim leading and trailing whitespace from post text encountered a specifically-spaced string in a user's post and triggered catastrophic backtracking. The site's application servers, each handling a fixed pool of worker threads, filled up with requests stuck evaluating that one regex, and the entire site became unresponsive to legitimate traffic. Both incidents share the same root cause profile: a regex that looked innocuous in code review, worked fine in every normal test case, and only revealed its exponential worst case when a particular input — sometimes accidental, sometimes crafted — showed up in production. That repeatability across unrelated companies, three years apart, is why security researchers treat ReDoS as a durable, recurring class of vulnerability rather than a one-off engineering mistake.

Which Widely-Used Open Source Packages Have Shipped ReDoS Vulnerabilities?

Several packages embedded deep in the JavaScript and Node.js supply chain have shipped exploitable ReDoS patterns, and because they sit low in dependency trees, each one affected thousands of downstream projects. CVE-2021-3765 hit nth-check, a CSS selector parser pulled in transitively by svgo and css-select, both of which sit underneath tools like webpack and react-scripts — meaning a huge share of the npm ecosystem inherited the flaw without any direct dependency on the vulnerable package. CVE-2022-25883 affected semver, arguably one of the most depended-upon packages in npm, where a crafted version-range string could trigger catastrophic backtracking during version comparison. CVE-2020-7662 hit marked, a popular Markdown-to-HTML parser, where a maliciously formatted list or heading string could hang the rendering process. In each case the vulnerable regex was written to solve an ordinary parsing problem, passed normal testing, and shipped for months or years before a security researcher found the pathological input that broke it. That pattern — quiet, mundane code with a hidden exponential edge case — is exactly what makes ReDoS a supply chain problem, not just an application bug.

What Makes a Regular Expression "Evil" in the First Place?

A regex becomes exploitable when it contains nested or overlapping quantifiers that let the same input be matched multiple different ways internally. The telltale structures are patterns like (a+)+, (a*)*, (a|a)+, or alternations with overlapping character classes such as (a|ab)*c — anywhere a quantified group contains another quantified group, or where two alternatives in a group can both match the same characters. When the string doesn't ultimately satisfy the full pattern, the backtracking engine has to unwind and retry every combination of how the inner group could have split the matched text, and the number of combinations grows exponentially with input length. This is why a 20-character non-matching string can take milliseconds while a 40-character one takes hours — the growth curve, not the input size, is the danger. These patterns show up constantly in real code because they're a natural way to express "one or more repeated groups" without the author realizing the ambiguity they've introduced; email validators, URL parsers, and whitespace trimmers are the three most common offenders found in vulnerability databases.

How Can Teams Catch ReDoS Before It Reaches Production?

Teams catch ReDoS by combining static analysis that flags dangerous regex structures with runtime safeguards that cap how long any single match is allowed to run. Static tools — including GitHub's CodeQL, the safe-regex and eslint-plugin-redos npm packages, and dedicated regex complexity analyzers — can parse a pattern's structure and flag nested quantifiers or ambiguous alternation before the code ever merges. On the runtime side, engines like Google's RE2 and Rust's regex crate guarantee linear-time matching by construction, trading a small set of backreference features for the elimination of catastrophic backtracking entirely; swapping a hot-path regex engine to one of these is often the highest-leverage fix available. For teams that can't switch engines, setting hard timeouts on regex evaluation (available natively in some runtimes, or via wrapper libraries in others) turns a potential outage into a bounded, recoverable failure. None of this works, though, if a vulnerable pattern is buried three dependencies deep and nobody knows it's there — which is the gap that actually causes incidents like Cloudflare's and Stack Overflow's.

How Safeguard Helps

Safeguard treats ReDoS the way it treats every other class of supply chain risk: as something that has to be found in the dependency graph, not just in first-party code. Safeguard's software composition analysis scans every package in a project's full dependency tree — including transitive dependencies like nth-check or semver sitting three or four levels removed from the direct manifest — and flags known ReDoS CVEs against the exact versions in use, with severity and reachability context so teams can prioritize the packages that actually process untrusted input. Beyond known-CVE matching, Safeguard's static analysis pipeline can be configured to detect the structural patterns that produce catastrophic backtracking — nested quantifiers, ambiguous alternation — in an organization's own codebase, catching a homegrown evil regex before it ever ships, the way the Cloudflare and Stack Overflow incidents were not caught. When a new ReDoS advisory is published, Safeguard maps it against every repository and build artifact under management, so security teams get a prioritized, evidence-backed list of what's affected instead of a manual grep across hundreds of services. For a vulnerability class where the fix is usually a one-line regex change but the blast radius can be a global outage, that speed from disclosure to remediation is the entire game.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.