Back to Blog
high SEVERITY4 min read

brace-expansion DoS: Exponential Backtracking in Nested Brace Patterns

A critical vulnerability in brace-expansion allows attackers to cause denial of service by submitting specially crafted patterns with nested braces. The exponential-time complexity in pattern expansion creates a computationally expensive path that can freeze applications processing user-controlled input.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published September 25, 2026•Reviewed September 30, 2026

Answer Summary

brace-expansion versions with unpatched brace pattern parsing are affected. An attacker can submit a crafted pattern with nested braces like `{a,b}{c,d}{e,f}...` repeated many times, causing exponential expansion that consumes all CPU and hangs the process. The fix implements algorithmic improvements to bound expansion complexity. The vulnerability is tracked as CVE-2026-13149 with no assigned CWE identifier.

Vulnerability at a Glance

cweN/A (unknown)
fixAlgorithmic improvement to limit pattern expansion complexity
riskApplication freeze and resource exhaustion from crafted input
languageJavaScript/Node.js
root causeUnbounded exponential expansion of nested brace patterns
vulnerabilityAlgorithmic Complexity Denial of Service

Affected Versions

Affected brace-expansion with unpatched brace pattern parsing (versions unknown)
Fixed in unknown
Ecosystem npm
CVE / GHSA CVE-2026-13149 / not assigned
CWE unknown

Introduction

A critical denial-of-service vulnerability reached production through a deceptively simple API: brace-expansion, the ubiquitous npm package that converts brace patterns like file-{a,b,c}.txt into expanded arrays. The flaw lies in how consecutive brace groups compound their expansion cost—each nested or sequential brace multiplies the output size exponentially rather than additively.

This vulnerability matters because brace-expansion sits at the heart of file globbing in build tools, test runners, and development servers. When user-controlled input reaches this parser without length or complexity limits, a single HTTP request can submit a pattern that generates billions of combinations, freezing the event loop and exhausting memory.

The Vulnerability Explained

The core issue is algorithmic: brace-expansion implements brace expansion using recursive generation that creates all possible combinations. Consider this innocent-looking pattern:

{a,b}{c,d}{e,f}{g,h}{i,j}{k,l}{m,n}{o,p}{q,r}{s,t}

This produces 2^10 = 1,024 results. Double the brace groups to 20, and you hit 1,048,576 expansions. At 30 groups, you're generating over a billion strings—enough to hang a Node.js process for minutes and consume gigabytes of memory.

The vulnerable code path processes each brace group independently, then computes the Cartesian product of all results. The implementation lacks:

  • Maximum expansion count limits
  • Input pattern complexity scoring
  • Early termination for exponential-growth patterns

An attacker exploiting CVE-2026-13149 could target any endpoint accepting glob patterns: file upload filters, build configuration APIs, or development server routes. The payload requires no special characters beyond braces and commas—making it easy to bypass naive input validation.

Real-world impact: A developer running webpack-dev-server or similar tools with live reload could have their entire development environment frozen by a single malicious WebSocket message or HTTP request containing a crafted brace pattern.

The Fix

The remediation for CVE-2026-13149 requires bounding the expansion algorithm's complexity. While the exact patched version remains unspecified, effective fixes typically implement:

  1. Maximum expansion limits: Abort when output would exceed a configurable threshold (commonly 10,000-100,000 results)
  2. Pattern complexity scoring: Reject or simplify patterns with consecutive brace groups exceeding safe depth
  3. Iterative expansion with early termination: Replace recursive generation with bounded iteration

For the related websocket-driver vulnerability (CVE-2026-54466) addressed in the same maintenance window, the fix was specific and verifiable:

-      "version": "0.7.4",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
-      "integrity": "[hash omitted]",
+      "version": "0.7.5",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz",
+      "integrity": "[hash omitted]",

The package.json changes forced this version across all Docusaurus packages using npm's overrides mechanism:

"overrides": {
  "@docusaurus/core": {
    "websocket-driver": "0.7.5"
  },
  "@docusaurus/plugin-client-redirects": {
    "websocket-driver": "0.7.5"
  }
}

This ensures transitive dependencies resolve to the patched version regardless of what individual packages declare.

Key Takeaways

  • Brace expansion is not free: Every consecutive brace group multiplies cost. Any API accepting brace patterns from untrusted input must implement expansion limits before calling brace-expansion.

  • Cartesian products explode silently: 20 brace groups with 2 options each exceeds a million expansions. Developers rarely consider this when accepting "simple" glob patterns from users.

  • npm overrides are security-critical: When vulnerable packages exist deep in transitive dependency trees, overrides in package.json is often the only practical remediation path.

  • Development tools are attack surfaces: webpack-dev-server, live reload servers, and build tools accept input that reaches pattern-matching libraries. These endpoints need the same input validation as production APIs.

  • Algorithmic DoS requires algorithmic defenses: Rate limiting and request timeouts help, but the only complete fix is bounding the expensive computation itself.

How Orbis AppSec Detected This

Source: User-controlled input reaching pattern expansion APIs (brace patterns in HTTP parameters, WebSocket messages, or configuration uploads)

Sink: brace-expansion library invoked without complexity bounds on the parsed pattern

Missing control: No maximum expansion limit, no pattern complexity validation, no input length restrictions on brace group count

CWE: unknown (algorithmic complexity issues lack a specific CWE identifier)

Fix: Implement expansion result limits and pattern complexity scoring before executing brace expansion on untrusted input

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-13149 exposes a fundamental tension in utility libraries: convenience versus safety. brace-expansion provides elegant, powerful pattern matching—but that power becomes a liability when exposed to adversarial input. The fix requires neither cryptographic expertise nor complex static analysis: simply bound the computation, validate the pattern complexity, and fail safely. For developers, the lesson is to audit every path where user input reaches pattern-matching libraries, no matter how "internal" the endpoint appears.

Prevention and further reading

Frequently Asked Questions

What specific brace pattern structure triggers the exponential expansion in brace-expansion?

Deeply nested alternating braces like `{a,b}{c,d}{e,f}` with many consecutive groups cause 2^n expansion. Each additional brace group doubles the output size, quickly exhausting memory and CPU.

Does the websocket-driver 0.7.5 upgrade address CVE-2026-13149 directly, or is this a transitive dependency fix?

The websocket-driver upgrade addresses CVE-2026-54466, a separate critical vulnerability. The brace-expansion fix (CVE-2026-13149) requires a direct upgrade of the brace-expansion package itself, not websocket-driver.

Why were npm package.json overrides needed for multiple @docusaurus packages to force websocket-driver 0.7.5?

Docusaurus core and plugins transitively depend on websocket-driver through live-server and webpack-dev-server. The overrides ensure all paths resolve to 0.7.5, preventing the vulnerable 0.7.4 from being selected by npm's dependency resolution algorithm.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #62

Related Articles

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.

critical

No Rate Limit on /api/uploads/presign Enables DoS

The `/api/uploads/presign` endpoint accepted unlimited concurrent requests to generate storage presigned URLs, giving an attacker a free lever to exhaust storage-provider quotas and server resources. The fix adds an `express-rate-limit` middleware capping each client to 30 requests per minute on that route.

high

CVE-2026-54673: builder-util-runtime Leaks Auth Headers on Redirect

electron-updater and electron-builder rely on builder-util-runtime to fetch update manifests and artifacts over HTTP. A flaw in that shared HTTP executor allowed credential headers attached to the original update-feed request to be re-sent after a redirect, exposing them to any host the redirect pointed to. The project fixes this by upgrading builder-util-runtime to 9.7.0 and collapsing a duplicate, older copy of the package that electron-updater had pinned on its own.

high

image-size 1.2.1 DoS: Zero-Valued Dimensions in Image Buffer Parser

A high-severity denial-of-service vulnerability in image-size 1.2.1 allows attackers to crash Node.js services using malicious image buffers with zero-valued dimensions. The fix removes the vulnerable `queue` dependency and tightens dimension validation in version 2.0.3.