Skip to solution
hardBackend

What is a ReDoS (Regular Expression Denial of Service) attack and how do you avoid it?

1.0k views
01

Understand the problem

Question presented to candidate: "Your API validates an email or username field with a regular expression, and one specific crafted input makes that single request take 30+ seconds while every OTHER request to your Node.js server also stalls. What's actually happening, and why does it affect requests that have nothing to do with the slow one?"

What a strong answer should cover:

  • A ReDoS attack exploits a regex with catastrophic backtracking — certain patterns (commonly nested/overlapping quantifiers, like (a+)+) cause the regex engine's matching attempts to grow exponentially with input length on specific crafted inputs, rather than the linear time most regex matching assumes.
  • 📌 Verified, not assumed: a real vulnerable regex (/^(a+)+$/), timed against escalating malicious input lengths, genuinely showed real, roughly exponential growth — 20 chars: 55ms, 22: 30ms, 24: 117ms, 26: 463ms — while a fixed, equivalent-but-safe regex (/^a+$/) handled an even longer (40-char) malicious input in a real 0ms. Extrapolating the same real growth rate, a modestly longer malicious input (40-50 chars) genuinely reaches multi-second or multi-minute matching time.
  • The second half of the prompt — why OTHER, unrelated requests also stall — is directly explained by Node's single-threaded event loop: regex matching runs synchronously, genuinely blocking the one thread that also handles every other concurrent request's JavaScript — a single slow .test()/.match() call genuinely freezes the entire server, not just the one request that triggered it.
  • 📌 Interview term: catastrophic backtracking — the specific regex-engine behavior (an ambiguous match with multiple ways to consume the same characters) that produces this exponential blowup; the fix is a regex that has only one way to match any given input — verified directly above, the safe /^a+$/ has no ambiguity to backtrack over at all.
  • The practical, layered mitigation, precise and complete: (1) rewrite the vulnerable pattern to remove the ambiguity (verified above, the direct fix); (2) where a pattern's safety can't be fully guaranteed by hand, use a regex-safety linting tool (eslint-plugin-redos or similar) to catch vulnerable patterns before they ship; (3) as a defense-in-depth backstop, enforce a maximum input length before ever running user input through any regex, and/or run regex matching with an explicit timeout (Node has no built-in regex timeout, so this typically means a worker-thread-based timeout wrapper for genuinely untrusted, unbounded input).

Clarifying questions expected:

  • "Is the vulnerable field's input length already bounded elsewhere (a form's max-length, a schema validator), or could a truly unbounded string reach this regex?" — a length cap alone often meaningfully reduces real-world exposure even without rewriting the pattern.
  • "Is this regex pattern user-defined/configurable at all (a customizable search filter, for instance), or fixed and code-reviewable?" — a user-controlled pattern is a genuinely harder, broader ReDoS surface than a fixed one.

Code / implementation expected: Yes — a real, measured exponential-growth demonstration against a real vulnerable regex, contrasted with a real safe regex staying fast on an even longer input, is the concrete, convincing proof of exactly why this attack works and that the fix genuinely resolves it.

nodejssecurityredosregex
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for Node.js security interviews — assumes familiarity with the event-loop-blocking concept from this bank's core Node.js questions. Difficulty: Hard

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:.

Solution ready — 2 min read

Classified // press E to declassify

04

Read the code

A real, measured ReDoS demonstration: exponential growth on a vulnerable regex vs. a safe regex staying fast
const vulnerableRegex = /^(a+)+$/;
const safeRegex = /^a+$/;

for (const n of [20, 22, 24, 26]) {
  const input = "a".repeat(n) + "!"; // deliberately non-matching, forces full backtracking
  const start = Date.now();
  vulnerableRegex.test(input);
  console.log(`vulnerable regex, input length ${n}: ${Date.now() - start}ms`);
}

const start = Date.now();
safeRegex.test("a".repeat(40) + "!");
console.log(`safe regex, input length 40: ${Date.now() - start}ms`);

// vulnerable regex, input length 20: 55ms
// vulnerable regex, input length 22: 30ms
// vulnerable regex, input length 24: 117ms
// vulnerable regex, input length 26: 463ms   <- genuinely exponential real growth
// safe regex, input length 40: 0ms            <- genuinely fast, no ambiguity to backtrack over
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 119 of 152 decoded in the Node.js track. One more won't hurt.

Back to track