{"schema":"threatline.record/2","record":{"id":"CVE-2026-102278","aliases":["GHSA-qhr7-859c-m2p7"],"summary":"brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion","details":"### Summary\n\n`expand_()` recurses once per level of brace *nesting*. Deeply nested input exhausts the native stack and crashes the process.\n\nThis is distinct from CVE-2026-14257 / GHSA-mh99-v99m-4gvg, which made the *tail* iterative (recursion on `m.post`, driven by how many groups are chained). Nesting depth drives a different recursion that the tail fix never touched, so the documented constant-stack-depth guarantee only ever covered chained input, not nested input.\n\nIt is also distinct from GHSA-6j4f-fj2g-mc7p, which fixed recursion in `parseCommaParts()`. Both payloads below still crash with that fix applied.\n\n### Two recursion sites\n\n**Comma members.** Each alternative of a brace set is expanded by a recursive call, so nesting a set inside every alternative recurses once per level:\n\n```js\nexpand('{a,'.repeat(4000) + 'z' + '}'.repeat(4000))\n// RangeError: Maximum call stack size exceeded\n```\n\nCrashes at depth 3,907 - about **15.6 KB** of input.\n\n**Single set.** A brace set whose body parses to a single part is expanded by a recursive call before being re-wrapped (`x{{a,b}}y` -> `x{a}y x{b}y`), which recurses once per nesting level:\n\n```js\nexpand('{'.repeat(3200) + 'a,b' + '}'.repeat(3200))\n// RangeError: Maximum call stack size exceeded\n```\n\nCrashes at depth 3,125 - about **6.25 KB** of input. This is the cheapest stack-exhaustion payload known against this package: roughly a quarter the input of GHSA-6j4f-fj2g-mc7p (29 KB), and about a tenth of minimatch's `MAX_PATTERN_LENGTH` (65,536).\n\n### Why `max` and `maxLength` do not help\n\nBoth crashes happen while recursing into sub-expansions, before the result set grows. The payloads produce almost no output - the single-set case yields 2 results - so neither bound is ever the limiter. `expand(payload, { max: 1, maxLength: 1 })` still overflows.\n\n### Impact\n\nAny application passing an untrusted string to `expand()`, directly or through `minimatch` / `glob` as a user-supplied glob pattern, can be crashed. In Node a `RangeError` the application does not catch terminates the process, so a server globbing user input is exposed to remote unauthenticated denial of service.\n\nAvailability only. No code execution, no data exposure.\n\n### Affected versions\n\nVerified affected on 1.1.18, 2.1.4, 3.0.6 and 5.0.9, at near-identical depths on every line (single set: 3,125 on all four; comma members: 3,907-4,102). Not a regression from any recent fix - the gap predates them.\n\n### Patch\n\nA `maxDepth` bound (default `EXPANSION_MAX_DEPTH`) is threaded through `expand_()`. Past the cap a group is treated as non-expanding and returned literally, which is how the parser already handles a group that cannot expand. This matches the existing `max` / `maxLength` caps, which truncate rather than throw, so `expand()` continues never to throw on any input.\n\nThe default sits far above any realistic nesting depth and well below the crash threshold.","categories":["Libraries & packages"],"product":"brace-expansion","vendor":"juliangruber","ecosystem":"npm","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":">= 4.0.0, < 5.0.11"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":">= 3.0.0, < 3.0.8"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":">= 2.0.0, < 2.1.6"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"range":"< 1.1.20"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-102278","source_modified_at":"2026-10-01T15:02:44.798Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"brace-expansion","vendor":"juliangruber","versions":[{"version":">= 4.0.0, < 5.0.11","status":"affected"},{"version":">= 3.0.0, < 3.0.8","status":"affected"},{"version":">= 2.0.0, < 2.1.6","status":"affected"},{"version":"< 1.1.20","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"ranges":[{"events":[{"introduced":"4.0.0"},{"fixed":"5.0.11"}],"type":"SEMVER"}],"versions":[]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"ranges":[{"events":[{"introduced":"3.0.0"},{"fixed":"3.0.8"}],"type":"SEMVER"}],"versions":[]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"ranges":[{"events":[{"introduced":"2.0.0"},{"fixed":"2.1.6"}],"type":"SEMVER"}],"versions":[]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"ranges":[{"events":[{"introduced":"0"},{"fixed":"1.1.20"}],"type":"SEMVER"}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"5.0.11"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"3.0.8"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"2.1.6"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-29T23:45:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion"},"version":"1.1.20"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"version":"5.0.11"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"version":"3.0.8"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"version":"2.1.6"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","source_modified_at":"2026-09-30T00:00:04.402763332Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"brace-expansion","purl":"pkg:npm/brace-expansion"},"version":"1.1.20"}],"cvss":7.5,"severity":"High","kev":{"listed":false},"epss":{"probability":0.0035,"percentile":0.27482,"score_date":"2026-10-23"},"published_at":"2026-09-28T20:57:09.850Z","modified_at":"2026-10-01T15:02:44.798Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-09-29T23:45:19Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-102278","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-01T15:02:44.798Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-09-30T00:00:04.402763332Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-102278","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-qhr7-859c-m2p7","tags":["x_refsource_CONFIRM"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102278","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/1efee7c397c191da6287a78ec19512476a966a7b","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/935d78f32f335b2ff76578e5c5e877d31ae9888c","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/juliangruber/brace-expansion/commit/de84f144e9816f30e25fc8179e2e1249ab6df0db","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-qhr7-859c-m2p7","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-10-01T15:02:35.975978Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-01T15:02:44.798Z","content_hash":"4b5863eaa1ed91c109e6ed2d8a67c455263f5d69542275503864526f6363bd4d"}}
