{
  "id": 18121746,
  "title": "A 28-Character String Freezes Your Regex for 3.6 Seconds",
  "url": "https://urgent.news/2026/11/04/a-28-character-string-freezes-your-regex-for-3-6-seconds",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-04T13:05:57.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/zhihu_wu_dea1d82af01a04d7/a-28-character-string-freezes-your-regex-for-36-seconds-2fi9"
  },
  "original_language": "en",
  "account": "A 28-character string can freeze a Node.js process for 3.6 seconds when using a specific regular expression pattern. This issue stems from catastrophic backtracking, which occurs when the regex pattern fails to match. The pattern /^(a+)+$/ attempts to match a string of 'a' characters followed by a single 'X' that causes the match to fail. The time taken by the Node process doubles with each additional character in the input string, taking roughly four hours for a 40-character input.\n\nThe problem lies in the nested quantifier (a+)+, which allows the regex engine to split the sequence of 'a' characters in every possible way, resulting in 2^(n-1) partitions for n characters. When the match fails, the engine must try all these partitions before giving up, leading to significant performance degradation. Even a seemingly simple email validator regex can exhibit the same slow behavior when appending a \"!\" to the pattern.\n\nSeveral attempts to address this issue have proven ineffective. Setting a length limit does not help, as real-world inputs can still reach the problematic length. Specifying an upper bound in the regex pattern also fails, as the number of splits increases exponentially rather than being capped. Possessive quantifiers, which would limit the engine's ability to backtrack, are not available in JavaScript's regex engine.\n\nThe recommended solution is to rewrite the regex pattern to have a single, unambiguous way of matching. This can be achieved by using a lookahead assertion and a backreference, such as /^a+$/ which matches a string of one or more 'a' characters without the catastrophic backtracking. This revised pattern can handle even extremely long inputs (35,000 times longer) in a fraction of the time taken by the original pattern.\n\nIf rewriting the regex is not feasible, an alternative approach is to emulate an atomic group using a lookahead and a backreference, as shown in the suggested pattern. This method can provide similar performance benefits. It is also important to impose limits on input length, run untrusted patterns within a worker environment with a timeout, or consider using a linear-time regex engine like RE2, which is resistant to catastrophic backtracking.",
  "summary": "Your test suite passes, staging passes, and then one user submits a 28-character string and a Node process pins a core for 3.6 seconds. I measured this today on Node 22 (V8) with /^(a+)+$/ against an input of n letters a followed by a single X that makes the match fail: input result time 20 chars no match 8.6 ms 22 chars no match 34.2 ms 24 chars no match 136.6 ms 26 chars no match 553.7 ms 27…",
  "key_points": [
    "28-character string freezes Node.js process for 3.6 seconds",
    "Catastrophic backtracking causes exponential slowdown",
    "Rewriting regex with lookahead assertion solves issue"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}