Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-13149

CVE-2026-13149: brace-expansion DoS Vulnerability

CVE-2026-13149 is a denial of service flaw in brace-expansion through 5.0.6 that causes exponential CPU consumption. This post covers the technical details, affected versions, impact, and mitigation strategies.

Published:

CVE-2026-13149 Overview

CVE-2026-13149 is a denial of service vulnerability in the brace-expansion npm package through version 5.0.6. The expand() function exhibits exponential-time complexity when processing consecutive non-expanding {} brace groups. An attacker who supplies a crafted string to expand(), directly or transitively through a dependent library, can trigger significant CPU consumption and block the Node.js event loop. The package's max option does not mitigate the issue, as it bounds output size rather than recursion work. This falls under [CWE-400] Uncontrolled Resource Consumption.

Critical Impact

Attackers can block the Node.js event loop and exhaust CPU resources through a single crafted input string passed to any code path that uses brace-expansion.

Affected Products

  • brace-expansion npm package versions through 5.0.6
  • Node.js applications that pass untrusted input to expand()
  • Downstream packages that transitively depend on brace-expansion (including minimatch and glob-based tooling)

Discovery Timeline

  • 2026-06-30 - CVE-2026-13149 published to NVD
  • 2026-06-30 - Last updated in NVD database

Technical Details for CVE-2026-13149

Vulnerability Analysis

The brace-expansion package parses and expands Bash-style brace patterns such as a{b,c}d into arrays of strings. The vulnerable expand_() function recursively processes each {...} group it encounters. When a brace group does not contain a comma or a numeric range, it is treated as non-expanding and rewritten before restarting the expansion.

The bug arises because each non-expanding {} group causes the function to recurse on the rewritten string. A sequence of consecutive non-expanding groups compounds this recursion, yielding exponential-time complexity relative to input length. The max option only caps the size of the produced output array; it does not cap intermediate recursion work, so a small input can still stall the process.

Root Cause

The root cause is uncontrolled recursion in the expansion algorithm. The function calls itself for each brace boundary rather than iterating, and no bound is placed on the total work performed. Because JavaScript is single-threaded, this CPU consumption directly blocks the event loop and degrades or halts service availability.

Attack Vector

An attacker submits a crafted string containing many consecutive non-expanding brace groups to any endpoint or API that ultimately invokes expand(). Common exposure paths include file-path matchers, configuration parsers, and CLI tooling built on minimatch or glob. No authentication is required if the vulnerable code processes user-supplied patterns.

typescript
// Patch excerpt from src/index.ts
// Before: recursive call for each non-expanding group
// After: loop iteratively to prevent stack/CPU exhaustion

  const expansions: string[] = []

-  const m = balanced('{', '}', str)
-  if (!m) return [str]
-
-  const pre = m.pre
-  const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']
-
-  if (/\$$/.test(m.pre)) {
-    for (let k = 0; k < post.length && k < max; k++) {
-      const expansion = pre + '{' + m.body + '}' + post[k]
-      expansions.push(expansion)
+  // The `{a},b}` rewrite below restarts expansion on a rewritten string with
+  // the same `max` and `isTop = true`. Loop instead of recursing so a long run
+  // of non-expanding `{}` groups can't exhaust the call stack.
+  for (;;) {
+    const m = balanced('{', '}', str)
+    if (!m) return [str]
+
+    const pre = m.pre
+
+    if (/\$$/.test(m.pre)) {
+      const post: string[] =
+        m.post.length ? expand_(m.post, max, false) : ['']
+      for (let k = 0; k < post.length && k < max; k++) {
+        const expansion = pre + '{' + m.body + '}' + post[k]
+        expansions.push(expansion)

Source: GitHub commit c7e33ec. The patch replaces recursion with iteration so consecutive non-expanding groups no longer compound work.

Detection Methods for CVE-2026-13149

Indicators of Compromise

  • Node.js worker or server processes pinned at 100% CPU on a single core with no forward progress in request logs.
  • Sudden increase in request latency or event-loop lag metrics correlated with pattern-matching or file-glob operations.
  • HTTP requests containing long runs of {} sequences in path, query, or body parameters that feed into glob or minimatch handlers.

Detection Strategies

  • Inventory node_modules and package-lock.json across build artifacts to identify direct and transitive brace-expansion versions at or below 5.0.6.
  • Use Software Composition Analysis (SCA) tooling to flag dependent packages such as minimatch, glob, and micromatch when they resolve a vulnerable brace-expansion.
  • Add Web Application Firewall (WAF) rules that detect inputs with high-density brace tokens forwarded to endpoints performing pattern matching.

Monitoring Recommendations

  • Instrument Node.js services with event-loop lag monitors and alert on sustained lag above baseline thresholds.
  • Track per-request CPU time for endpoints that parse user-supplied glob or brace patterns.
  • Log and sample inputs that exceed length or brace-count thresholds for offline review.

How to Mitigate CVE-2026-13149

Immediate Actions Required

  • Upgrade brace-expansion to a patched release that includes the iterative expansion fix from commit c7e33ec.
  • Refresh package-lock.json and rebuild container images to ensure transitive dependencies resolve to the patched version.
  • Validate and length-limit any user-controlled string passed to glob, minimatch, or brace expansion APIs.

Patch Information

The fix is available in the upstream repository. Review the GitHub commit on brace-expansion and install the corrected release from the brace-expansion npm package. Update pinned versions in package.json and run npm audit fix to propagate the change to transitive dependents.

Workarounds

  • Reject or truncate input strings that exceed a conservative length before passing them to expand().
  • Wrap calls to expand() inside a worker thread with a hard timeout so a stall does not block the main event loop.
  • Disallow brace patterns entirely in externally reachable endpoints when they are not required by the business logic.
bash
# Update brace-expansion and verify no vulnerable versions remain
npm update brace-expansion
npm ls brace-expansion
npm audit --production

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.