The vulnerability, CVE-2026-102278, in the brace-expansion library is a Denial of Service (DoS) caused by uncontrolled recursion. The core issue lies in the recursive nature of the expand (and expand_ in TypeScript) function when processing deeply nested brace groups. Specifically, two scenarios lead to excessive recursion:
- Comma members: When a brace set contains nested sets within its comma-separated alternatives (e.g.,
{a,{b,c},d}). Each alternative's expansion triggers a recursive call.
- Single set re-wrapping: When a brace set's body parses to a single part, it's re-wrapped, leading to another recursive call (e.g.,
x{{a,b}}y expands to x{a}y x{b}y).
In both cases, without a depth limit, a specially crafted input string with sufficient nesting (e.g., '{'.repeat(3200) + 'a,b' + '}'.repeat(3200)) would cause the JavaScript call stack to overflow, resulting in a RangeError: Maximum call stack size exceeded and crashing the Node.js process. This constitutes a remote unauthenticated DoS if user-supplied input is passed to expand().
The patches introduce a maxDepth option, which defaults to EXPANSION_MAX_DEPTH (1000). This maxDepth parameter is passed down through the call chain to the recursive expand (or expand_) function. Inside this recursive function, a check if (depth > maxDepth) is added. If the recursion depth exceeds this limit, the function stops expanding and returns the literal string, effectively truncating the expansion rather than throwing an error. This prevents stack exhaustion while maintaining the package's behavior of not throwing exceptions for invalid or overly complex patterns.
The identified vulnerable functions are expand (in index.js for older versions) and expand_ (in src/index.ts for newer, TypeScript-based versions), as these are the functions containing the recursive logic that lacked the depth check. The expandTop (in index.js) and the exported expand (in src/index.ts) functions are also included because they are the public entry points that initiate the vulnerable recursive process and were modified to pass the new maxDepth parameter, thus directly participating in the fix of the vulnerability.