Join our Newsletter — 33% off our NHI Course

Why do overlapping regex alternations create ReDoS risk in sanitization code?

Overlapping alternations create risk because the regex engine can match the same input in multiple ways, then backtrack repeatedly when a later token fails. If that pattern sits inside a quantifier and the expression is anchored at the end, the engine may explore exponential paths. That combination is what turns a normal match into denial of service.

Why overlapping alternations turn sanitizers into a performance hazard

Sanitization code often looks harmless because it is written to remove or normalise input, not to accept complex business logic. The problem is that regular expressions are still executed by a backtracking engine, so an apparently simple pattern can consume large amounts of CPU when multiple alternatives overlap. That makes the sanitizer itself part of the attack surface, especially when the input is attacker-controlled and the regex is invoked on every request.

For a deeper control-oriented view of how organisations should manage this kind of risk, the NIST Cybersecurity Framework 2.0 is useful as a general resilience reference, but the core issue here is not policy design. It is the mismatch between a permissive pattern and an engine that must search through many equivalent matches before it can prove failure.

The practical mistake is assuming that sanitization regexes are “safe” because they only remove characters or tags. In practice, teams often discover the cost of overlap only after malformed input begins tying up worker threads or request handlers under load.

How the engine gets trapped in repeated backtracking

Overlapping alternations create ambiguity. If one branch can consume the same prefix as another branch, the engine may choose one path, discover that a later token fails, then rewind and try another path. That is manageable when the alternation is small and the input is short. It becomes dangerous when the alternation is repeated, nested inside a quantifier, or combined with anchors that force the engine to search for a full match before it can stop.

In sanitization code, this pattern is common when developers try to match a broad family of disallowed inputs with one expression. A few examples of the failure pattern are:

  • alternatives that share long prefixes, so multiple branches fit the same text
  • nested quantifiers that let the engine revisit the same span many times
  • anchored expressions that prevent early acceptance and force a full exploration of possibilities
  • large attacker-controlled strings that magnify the cost of each failed branch

The important operational point is that ReDoS is not caused by “regex” in general. It is caused by a specific search shape that multiplies work as the input grows. A sanitizer that is fast on ordinary user data can still become a bottleneck when the input is crafted to trigger the worst-case path. That is why safe-looking cleanup code should be treated as latency-sensitive code, not as a trivial preprocessing step.

Teams should also remember that sanitization patterns often run before authentication, before rate limiting, or before application-level validation. That placement increases exposure because the expensive work happens early and can be repeated many times by a single source. Where possible, simpler tokenisation, explicit parsing, or a non-backtracking regex feature set is more predictable than a broad alternation meant to catch everything at once.

Where the simple rule breaks down in real code

Tighter matching often increases maintenance overhead, requiring teams to balance readability against the need to avoid ambiguous paths.

There is a genuine tradeoff here. A regex that is too broad may be risky, but a regex that is too narrow can miss malformed input or force developers to bolt on extra special cases. The right answer depends on what the sanitizer is trying to do. Consensus is clear that regex should not be used as a parser, but there is less agreement on how much sanitization logic should remain in pattern form versus being moved into explicit code.

Edge cases matter when the pattern is reused across fields with different input shapes. A pattern that is acceptable for short identifiers may be dangerous for free-text fields, log ingestion, or API payloads. The same applies when the code is embedded in a high-volume path, because even a modest backtracking cost can become visible at scale. This is why performance testing must include worst-case and adversarial strings, not just ordinary examples.

If the pattern can be simplified into mutually exclusive branches, that is usually safer than relying on the engine to sort out overlap. Where that is not possible, the code should be reviewed as a potential availability dependency, because the failure mode is not incorrect output alone but loss of service capacity.

Risk and Threat Considerations

ReDoS in sanitization code is an availability risk. The main exposure is that user-controlled input can trigger disproportionate CPU usage in a request path that is supposed to be lightweight, which can reduce throughput and create queueing across shared workers or threads.

Failure mechanism: Overlapping alternations expand the number of plausible match paths, and backtracking engines revisit those paths when later tokens fail. When the pattern is repeated, anchored, or applied to long inputs, the search space can grow rapidly enough to stall the process.

Impact: The practical effect is latency spikes, request timeouts, and in severe cases denial of service for the application or service tier that performs the sanitization.

Standards & Framework Alignment

This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.

MITRE ATT&CK address the attack and risk surface, while NIST CSF 2.0 and CIS Controls v8 set the governance and control requirements practitioners need to meet.

Framework Control / Reference Relevance
NIST CSF 2.0 PR.IP-1 — Baseline Configuration Management Sanitization regexes need controlled, reviewed patterns to avoid unsafe changes.
DE.CM-8 — Vulnerability monitoring ReDoS emerges as a detectable application weakness under adversarial input.
Recommendation — Apply controlled review to regex sanitizers before deploying pattern changes. Monitor for regex-driven latency spikes and investigate them as application weaknesses.
CIS Controls v8 16 — Application Software Security Unsafe sanitization regexes are an application-security defect needing testing.
Recommendation — Test sanitization regexes for worst-case execution before release.
MITRE ATT&CK T1499 — Endpoint Denial of Service ReDoS can exhaust CPU and deny service through crafted input.
Recommendation — Treat exploitable regex backtracking as a denial-of-service attack path.

Practitioner Guidance

What to verify: Test the exact regex against worst-case strings, not just valid samples, and confirm whether a small increase in input length causes a disproportionate jump in execution time. If it does, treat the pattern as unsafe for production sanitization.

What good looks like: The sanitization path should have predictable runtime on malformed input, and the pattern should avoid ambiguous branches wherever possible. If the logic cannot be made deterministic enough, move the risky part out of regex and into explicit code that is easier to reason about.

Practitioner takeaway: Overlap is dangerous not because a regex is complex, but because ambiguity gives the engine room to do extra work on attacker-controlled input.