Regex (Double-edged sword) Cloudflare outage

Regex (Double-edged sword) Cloudflare outage


Regex Is Executable Code

Regex is often treated like a string filter. It isn’t.

Regex is executable logic that runs on your hottest paths — routers, validators, WAFs, parsers. A single bad pattern can take down production.

One such pattern is:

.*.*=.*

In 2019, this exact class of regex caused a massive global outage at Cloudflare. Here is how a few characters of "code" broke the internet.

The Anatomy of Catastrophic Backtracking

To understand why .*.*=.* is dangerous, we have to look at how the regex engine tries to match a string.

The .* operator is greedy. It tries to match as much as possible. When you stack two greedy matchers together (.*.*), you create an exponential number of ways for the engine to try and satisfy the pattern.

How the Engine "Panics"

Imagine checking the string abc against .*.*=.*:

  1. The first .* matches abc.
  2. The second .* matches nothing.
  3. The engine looks for a =. It's not there.
  4. Backtrack: The first .* gives up a character and matches ab.
  5. The second .* tries to match c.
  6. Still no =.
  7. Backtrack again: The engine tries every possible combination of splitting the string between those two .* symbols.

As the input string grows linearly (e.g., a long URL or a POST body), the number of combinations the engine must check grows exponentially. This is known as Catastrophic Backtracking.

In the Cloudflare case, a single CPU core would hit 100% utilization trying to resolve a single request, eventually leading to a "deadly embrace" where all available resources were exhausted across the global network.

Safe Patterns: How to Write Regex at Scale

If you are running regex at the edge or in high-traffic microservices, you must follow these safety rules:

  1. Avoid Nested Quantifiers Never nest or stack repetitions like (a+)+ or ... If you need to match anything before a specific character, be more specific.
  2. Use Non-Greedy Matchers Use .? instead of . when possible. This tells the engine to match the smallest amount of text possible before moving to the next part of the pattern.
  3. Favour "Negative Character Classes" Instead of saying "match anything until an equals sign" with .*=, use: Code snippet
[^=]*=

This tells the engine: "Match any character that is not an equals sign, then match the equals sign." This eliminates backtracking because there is only one way to satisfy the logic. 4. Use Timeouts Never run regex on a production server without a timeout mechanism. Most modern languages (Python, Go, .NET) allow you to pass a timeout or match_limit to the regex engine.

Regex is a power tool. Used correctly, it solves complex parsing problems in a single line. Used incorrectly, it’s a self-inflicted Denial of Service (DoS) attack. Next time you write a "simple" pattern for a WAF or a router, ask yourself: "What happens if the match fails at the very last character?" If the answer involves the engine re-calculating the universe, it's time to refactor.