GitHub Advisoryadvisory · npm
GHSA-6j4f-fj2g-mc7p brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion
HIGH
Official page ↗
- Aliases
- CVE-2026-102276
- Ecosystem
- npm
- Packages
- brace-expansion
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
- Weaknesses
- CWE-400, CWE-674
- Reviewed
- 2026-09-29
Affected packages
• npm brace-expansion: >= 4.0.0, < 5.0.10 → fixed in 5.0.10
• npm brace-expansion: >= 3.0.0, < 3.0.7 → fixed in 3.0.7
• npm brace-expansion: >= 2.0.0, < 2.1.5 → fixed in 2.1.5
• npm brace-expansion: < 1.1.19 → fixed in 1.1.19
Description
Summary
`parseCommaParts()` can exhaust the native stack and crash the process. There are two distinct ways to trigger it, both reachable from a single untrusted pattern string.
This is the parsing-side counterpart to CVE-2026-14257 / GHSA-mh99-v99m-4gvg. That fix made `expand_()` iterative and documented a constant-stack-depth guarantee, but `parseCommaParts()` was left recursive, so the guarantee only held for one of the two parsing paths.
Vector 1 - unbounded recursion on `post`
`parseCommaParts()` recursed on the remainder of the string once per brace group:
```js
const postParts = parseCommaParts(post) // unbounded
```
A brace group containing many comma-separated groups drives one recursion level per group:
```js
expand('{' + '{a},'.repeat(7000) + 'b}')
// RangeError: Maximum call stack size exceeded
```
About 7,300 repetitions - roughly 29 KB of input - is enough on Node 24; roughly 6,300 (25 KB) on Node 18. The threshold is identical on every affected release line.
Vector 2 - `push.apply` with an unbounded array
Even with the recursion removed, `parseCommaParts()` spread whole arrays into an argument list:
```js
p.push.apply(p, postParts)
parts.push.apply(parts, p)
```
`Function.prototype.apply` places one argument per element on the stack, so a single large array overflows it. This needs no recursion depth at all - the following reaches a recursion depth of exactly 1:
```js
expand('{{x},' + 'a,'.repeat(125000) + 'b}')
// RangeError: Maximum call stack size exceeded
```
Threshold is about 124,300 repetitions (~249 KB). This vector was not part of the original report; it was found while verifying the fix. A patch that only de-recurses but keeps `push.apply` leaves a working denial of service behind.
Why `max` and `maxLength` do not help
Both crashes happen during parsing, before any expansion. The payloads produce one result per group, so output size grows linearly with input and is never the limiter. `expand(payload, { max: 1, maxLength: 1 })` still overflows.
Impact
Any application that passes an untrusted string to `expand()` - directly, or through `minimatch` / `glob` where it is a user-supplied glob pattern - can be crashed. In Node, a `RangeError` that the application does not catch terminates the process, so a server that globs user input is exposed to remote unauthenticated denial of service.
`minimatch`'s own `MAX_PATTERN_LENGTH` cap (65,536) does not help against vector 1: the overflow threshold sits well below it. Confirmed on minimatch 10.2.6 - a 64,003-byte pattern passes the length check and overflows both `minimatch.braceExpand()` and `new minimatch.Minimatch()`.
This is an availability-only issue. No code execution and no data exposure.
Not a regression
5.0.8 and 5.0.9 overflow at the same repetition count, so the gap predates the recent advisories; those fixes simply did not reach it. Verified affected on 1.1.18, 2.1.4, 3.0.6, 5.0.8 and 5.0.9, all at an identical threshold.
Patch
`parseCommaParts()` is rewritten as a loop that carries the partial part across chunks, and every array append uses an element-by-element loop rather than `push.apply`. The redundant `if (!str) return ['']` guard is dropped - the loop returns `['']` for the empty string on its own.
Equivalence of the old and new implementations was checked by differential testing: exhaustive over every string of `{`, `}`, `,`, `a` up to length 7 plus 300,000 random inputs - 322,000 cases, zero mismatches.
Severity note
Scored 7.5 High under CVSS 3.1 for consistency with the other availability advisories on this package (GHSA-mh99-v99m-4gvg, GHSA-rgw5-rvv9-x895), which use the same vector. The reporter self-assessed 6.9 Medium under CVSS 4.0 (`CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N`).
Credit
Reported by baeseungwon1010, with a working proof of concept and a proposed patch. Vector 2 was identified during maintainer verification.
Related
Alias · CVE (1)
- CVE-2026-102276 The brace-expansion library generates arbitrary strings containing a common prefix and suffix. vulnerability
References
- https://github.com/juliangruber/brace-expansion/security/advisories/GHSA-6j4f-fj2g-mc7p web
- https://nvd.nist.gov/vuln/detail/CVE-2026-102276 advisory
- https://github.com/juliangruber/brace-expansion/commit/0bcbfc0a5928c3073d48f42999d1ce4fc1c42fbc web
- https://github.com/juliangruber/brace-expansion/commit/316359e6019c39b3254c8ba8e25dc586a480652c web
- https://github.com/juliangruber/brace-expansion/commit/5171e681c0922b7ae8bfaf9a331e309107be6edc web
- https://github.com/juliangruber/brace-expansion/commit/6735c94873ca570bcdd6a0690033bdd3126379d3 web
- https://github.com/juliangruber/brace-expansion package