Back to Blog
high SEVERITY5 min read

brace-expansion Stack Exhaustion: CVE-2026-102276 Patched

A critical stack exhaustion vulnerability in brace-expansion allows attackers to crash Node.js applications by supplying specially crafted brace patterns that trigger unbounded recursion. The fix upgrades the library across all maintained version lines to enforce depth limits on recursive expansion. This vulnerability affects any service that expands user-controlled brace patterns without input validation.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published October 2, 2026•Reviewed October 2, 2026

Answer Summary

brace-expansion versions before 5.0.12, 3.0.7, 2.1.5, and 1.1.19 are vulnerable to stack exhaustion via deeply nested or recursive brace patterns. An attacker can craft a brace pattern that causes the parser to recurse unbounded, exhausting the call stack and terminating the Node.js process. The fix enforces recursion depth limits in the expansion algorithm and is available in brace-expansion 5.0.12, 3.0.7, 2.1.5, and 1.1.19. CWE is unknown.

Vulnerability at a Glance

cweN/A
fixEnforce maximum recursion depth during brace expansion
riskDenial of service; process crash on crafted input
languageJavaScript
root causeBrace pattern expansion lacked recursion depth limits, allowing deeply nested patterns to exhaust the stack
vulnerabilityStack exhaustion via unbounded recursion

Stack Exhaustion in brace-expansion: CVE-2026-102276

What was fixed

The brace-expansion library, which powers glob pattern matching and string expansion across the Node.js ecosystem, contained a critical stack exhaustion vulnerability. Attackers could supply carefully crafted brace patterns—such as deeply nested or recursive braces—that would cause the parser to recurse unbounded, exhausting the V8 JavaScript engine's call stack and crashing the process. The vulnerability is now patched in multiple version lines: 5.0.12, 3.0.7, 2.1.5, and 1.1.19.

Affected Versions

Affected < 5.0.12, < 3.0.7, < 2.1.5, < 1.1.19 (depending on major version)
Fixed in 5.0.12, 3.0.7, 2.1.5, 1.1.19
Ecosystem npm
CVE / GHSA CVE-2026-102276
CWE unknown

If you depend on brace-expansion indirectly through minimatch, glob, or other packages, you likely inherited one of these versions. Verify your exact dependency by checking package-lock.json or running npm list brace-expansion.

The Vulnerability Explained

The brace-expansion library parses brace patterns like {a,b,c} and expands them into separate strings: ["a", "b", "c"]. This is a core utility for glob matching, used by build tools, test runners, and file processors across the Node.js ecosystem.

The vulnerability lies in how the library handled nested braces. When expanding a pattern, the parser would recursively call itself to handle sub-patterns. However, there was no limit on recursion depth. An attacker could exploit this by supplying a pathological pattern:

// Example: deeply nested braces
"{a,{b,{c,{d,{e,{f,{g,{h,{i,{j,{k,{l,{m,{n,{o,{p,{q,{r,{s,{t,{u,{v,{w,{x,{y,{z}}}}}}}}}}}}}}}}}}}}}}}}}}"

Each layer of nesting causes a new recursive call. With enough depth—or a more sophisticated pattern crafted to trigger the worst-case recursion path—the call stack would overflow:

RangeError: Maximum call stack size exceeded

The Node.js process would crash immediately, unable to recover or handle the exception gracefully.

Real-world impact

Consider a web service that accepts a pattern parameter and expands it to customize build output or file matching:

// Example: a vulnerable API endpoint
app.get('/expand', (req, res) => {
  const pattern = req.query.pattern; // User-controlled input
  const expanded = require('brace-expansion')(pattern);
  res.json({ result: expanded });
});

An attacker could send a request with a deeply nested brace pattern:

GET /expand?pattern={a,{b,{c,...(repeat 1000 times)...}}}

The service would attempt to expand the pattern, recurse until the stack was exhausted, and crash. The process would be unavailable until restarted. If not load-balanced, this is a complete denial of service.

The Fix

The patched versions enforce a maximum recursion depth during brace expansion. When the parser encounters a recursion depth exceeding a safe threshold (typically a few hundred levels), it stops and either returns the pattern as-is or throws a controlled error, rather than crashing the process.

The version upgrade from 5.0.9 to 5.0.12 (and corresponding upgrades in the 1.1.x, 2.1.x, and 3.0.x lines) embeds this depth-limit check:

// Before (vulnerable): no depth check
function expand(pattern, options) {
  // ... parse and recurse without limit ...
}

// After (fixed): enforces depth limit
function expand(pattern, options) {
  const maxDepth = options.maxDepth || 1000; // or similar limit
  return expandWithDepth(pattern, 0, maxDepth);
}

function expandWithDepth(pattern, currentDepth, maxDepth) {
  if (currentDepth > maxDepth) {
    throw new Error('Brace expansion depth limit exceeded');
  }
  // ... parse and recurse, incrementing currentDepth ...
}

This prevents the unbounded recursion that led to stack exhaustion.

Why multiple version bumps?

The fix was released across four separate version lines because brace-expansion is used by multiple major versions of dependent packages:

  • brace-expansion 1.1.x is used by older minimatch releases (v7 and earlier)
  • brace-expansion 2.1.x is used by minimatch v8
  • brace-expansion 3.0.x serves some specialized consumers
  • brace-expansion 5.0.x is used by minimatch v9

Each major version of minimatch has its own dependency constraint on brace-expansion (e.g., ^2.1.0 or ^5.0.0). To ensure all users receive the fix without forcing unnecessary major-version upgrades, the maintainers patched all active lines. Upgrading your project simply requires running npm update, which will pull the patched version within your existing dependency constraint.

Key Takeaways

  • Recursion depth is not a free resource. Even simple recursive algorithms can become exploitable DoS vectors if an attacker can control the input depth. Always enforce a maximum recursion depth in parsers and expansion routines.

  • Unbounded recursion is silent until it fails catastrophically. Unlike memory leaks or resource exhaustion that might be caught in testing, stack overflow can occur suddenly on production data, and the process terminates immediately. Depth limits should be defensive defaults, not reactive fixes.

  • Transitive dependencies matter for availability. brace-expansion is used by glob, minimatch, and dozens of downstream libraries. A crash in a transitive dependency can bring down your entire application. Regularly audit your dependency tree (e.g., npm audit) and subscribe to security updates.

  • Version-specific patches preserve compatibility. By releasing the fix across all active major versions, the maintainers ensured that users could upgrade without forcing a simultaneous migration of dependent packages. This is a best practice for widely-used utilities.

  • Validate input depth in user-facing APIs. If your code expands patterns, globs, or braces from user input, add your own depth validation before passing to the library. A simple length check or nesting-level counter can catch pathological inputs early.

How Orbis AppSec Detected This

Source: The brace-expansion library entry point, which accepts untrusted pattern strings from any caller.

Sink: The recursive expansion function that processes nested brace sub-patterns without a depth limit.

Missing control: No maximum recursion depth parameter or check; the algorithm could recurse indefinitely as long as the input contained nested braces.

CWE: unknown (but commonly mapped to CWE-674: Uncontrolled Recursion).

Fix: Enforce a configurable recursion depth limit and reject patterns exceeding the threshold.

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-102276 is a reminder that even simple utilities can harbor availability risks. Stack exhaustion through unbounded recursion is a preventable class of denial-of-service flaw—one that appears obvious in hindsight but is easy to overlook when building a parsing or expansion library. By upgrading brace-expansion to 5.0.12, 3.0.7, 2.1.5, or 1.1.19, and by implementing your own input-depth guards in services that accept patterns, you eliminate both the immediate risk and the architectural vulnerability that created it.

Prevention and further reading

Frequently Asked Questions

Why did the fix require multiple version bumps (5.0.12, 3.0.7, 2.1.5, 1.1.19) instead of a single release?

brace-expansion maintains multiple major version lines to support different dependency chains. The 1.1.x, 2.1.x, 3.0.x, and 5.0.x versions have separate maintenance branches; each received the stack exhaustion fix independently to avoid breaking semver contracts or introducing incompatibilities with their respective consumers (e.g., minimatch v8 uses 2.1.x, v9 uses 5.0.x).

Can an attacker trigger this vulnerability through a URL or HTTP parameter if my service expands brace patterns from user input?

Yes. If your code calls the brace-expansion library on request parameters—for example, expanding `{a,{b,{c,{d,...}}}}` from a query string—an attacker can craft a pattern deep enough to exhaust the call stack before the function returns, crashing the process and achieving denial of service.

Does updating to brace-expansion 5.0.12 from 5.0.9 require code changes?

No. The fix is backward compatible; upgrading replaces the vulnerable library with the patched version. No API changes or code rewrites are necessary.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #145

Related Articles

high

PostCSS 8.5.12: Arbitrary File Read via sourceMappingURL

PostCSS versions prior to 8.5.12 contain an information disclosure vulnerability that allows attackers to read arbitrary files from the host system by crafting malicious CSS with a specially-formed sourceMappingURL comment. This vulnerability affects any application that processes untrusted CSS input, including CSS-in-JS frameworks, build tools, and web servers that normalize or transpile user-provided stylesheets.

critical

BFF Proxy QR Code Endpoint Prototype Pollution via Unvalidated JSON

A critical prototype pollution vulnerability in a backend-for-frontend (BFF) proxy endpoint allowed attackers to inject malicious properties into the JavaScript Object prototype by crafting JSON requests with forbidden keys. This could compromise application behavior across all objects. The fix adds explicit key validation to reject payloads containing `__proto__`, `constructor`, or `prototype`.

high

smol-toml 1.7.0 DoS: Malformed TOML Documents Crash Parser

A denial-of-service vulnerability in smol-toml 1.7.0 allows attackers to crash the parser by supplying malformed TOML documents. The vulnerability affects any application that parses untrusted TOML input. The fix, available in smol-toml 1.7.1, hardens input validation and error recovery.

high

JOSMFileHack TransformerFactory XXE: External DTD Processing Enabled

OSM2World's JOSMFileHack utility, which processed OpenStreetMap files generated by the JOSM editor, contained an insecure TransformerFactory configuration that permitted external DTD and stylesheet access. The vulnerability was resolved by completely removing the vulnerable code path rather than hardening it in place.

critical

LDAP Filter Injection in da_unique_email_validator Fixed

The registration-time email uniqueness validator, `da_unique_email_validator`, formatted the submitted email address straight into an LDAP search filter with Python's `%` operator, so filter metacharacters in the email were interpreted as filter syntax. The fix wraps the value in `ldap.filter.escape_filter_chars()` (and imports the `ldap.filter` submodule explicitly), so a submitted address is always treated as a literal attribute value. Any deployment with `ldap login` enabled and a bind accoun

high

Voice Assistant Widget XSS: Unsanitized Bot Messages Execute in

The voice assistant widget's `appendMessage` function had a critical cross-site scripting (XSS) vulnerability where bot messages were inserted directly into the DOM without sanitization, while user messages were escaped. An attacker controlling bot responses could inject and execute arbitrary JavaScript in the user's browser context. The fix applies HTML escaping to all message types uniformly.