{"schema":"threatline.record/2","record":{"id":"CVE-2026-102276","aliases":["GHSA-6j4f-fj2g-mc7p"],"summary":"brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion","details":"### Summary\n\n`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.\n\nThis 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.\n\n### Vector 1 - unbounded recursion on `post`\n\n`parseCommaParts()` recursed on the remainder of the string once per brace group:\n\n```js\nconst postParts = parseCommaParts(post)   // unbounded\n```\n\nA brace group containing many comma-separated groups drives one recursion level per group:\n\n```js\nexpand('{' + '{a},'.repeat(7000) + 'b}')\n// RangeError: Maximum call stack size exceeded\n```\n\nAbout 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.\n\n### Vector 2 - `push.apply` with an unbounded array\n\nEven with the recursion removed, `parseCommaParts()` spread whole arrays into an argument list:\n\n```js\np.push.apply(p, postParts)\nparts.push.apply(parts, p)\n```\n\n`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:\n\n```js\nexpand('{{x},' + 'a,'.repeat(125000) + 'b}')\n// RangeError: Maximum call stack size exceeded\n```\n\nThreshold 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.\n\n### Why `max` and `maxLength` do not help\n\nBoth 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.\n\n### Impact\n\nAny 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.\n\n`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()`.\n\nThis is an availability-only issue. No code execution and no data exposure.\n\n### Not a regression\n\n5.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.\n\n### Patch\n\n`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.\n\nEquivalence 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.\n\n### Severity note\n\nScored 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`).\n\n### Credit\n\nReported by baeseungwon1010, with a working proof of concept and a proposed patch. Vector 2 was identified during maintainer verification.","categories":["Libraries & packages"],"product":"brace-expansion","vendor":"juliangruber","ecosystem":"npm","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":">= 4.0.0, < 5.0.10"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":">= 3.0.0, < 3.0.7"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":">= 2.0.0, < 2.1.5"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":"< 1.1.19"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-102276","source_modified_at":"2026-09-29T13:38:29.919Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"brace-expansion","vendor":"juliangruber","versions":[{"status":"affected","version":">= 4.0.0, < 5.0.10"},{"status":"affected","version":">= 3.0.0, < 3.0.7"},{"status":"affected","version":">= 2.0.0, < 2.1.5"},{"status":"affected","version":"< 1.1.19"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"ranges":[{"type":"SEMVER","events":[{"introduced":"4.0.0"},{"fixed":"5.0.10"}]}],"versions":[]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"ranges":[{"type":"SEMVER","events":[{"introduced":"3.0.0"},{"fixed":"3.0.7"}]}],"versions":[]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"ranges":[{"type":"SEMVER","events":[{"introduced":"2.0.0"},{"fixed":"2.1.5"}]}],"versions":[]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.1.19"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"5.0.10"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"3.0.7"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"2.1.5"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-29T23:44:59Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"1.1.19"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"version":"5.0.10"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"version":"3.0.7"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"version":"2.1.5"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","source_modified_at":"2026-09-30T00:00:03.836613572Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"brace-expansion","ecosystem":"npm","purl":"pkg:npm/brace-expansion"},"version":"1.1.19"}],"cvss":7.5,"severity":"High","kev":{"listed":false},"epss":{"probability":0.0035,"percentile":0.27481,"score_date":"2026-10-23"},"published_at":"2026-09-28T20:50:59.984Z","modified_at":"2026-09-30T00:00:03.836613572Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-09-29T23:44:59Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-102276","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-09-29T13:38:29.919Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p","fetched_at":"2026-10-23T18:48:36.087640Z","source_modified_at":"2026-09-30T00:00:03.836613572Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-102276","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/security/advisories/GHSA-6j4f-fj2g-mc7p","tags":["x_refsource_CONFIRM"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102276","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/0bcbfc0a5928c3073d48f42999d1ce4fc1c42fbc","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/316359e6019c39b3254c8ba8e25dc586a480652c","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/5171e681c0922b7ae8bfaf9a331e309107be6edc","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/6735c94873ca570bcdd6a0690033bdd3126379d3","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-6j4f-fj2g-mc7p","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"none","automatable":"yes","technical_impact":"partial","assessed_at":"2026-09-29T13:37:06.086529Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-09-30T00:00:03.836613572Z","content_hash":"6601e78a9b9e8c00a478a43fed9e15aae606e5abcb86daffab8be9cea42eddc9"}}
