Skip to content

chore(deps): update dependency brace-expansion to v5.0.7 [security] - #124

Open
renovate[bot] wants to merge 1 commit into
developfrom
renovate/npm-brace-expansion-vulnerability
Open

chore(deps): update dependency brace-expansion to v5.0.7 [security]#124
renovate[bot] wants to merge 1 commit into
developfrom
renovate/npm-brace-expansion-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
brace-expansion 5.0.65.0.7 age confidence

brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups

CVE-2026-13149 / GHSA-3jxr-9vmj-r5cp

More information

Details

Summary

brace-expansion's expand() exhibits exponential-time - O(2ⁿ) - behavior in the number of consecutive non-expanding {} groups. A short, all-ASCII input (~90 bytes/30 groups) blocks the calling thread for minutes; a slightly longer input hangs it effectively indefinitely. Because the dominant consumers run on Node's single-threaded event loop, one small input can fully stall a worker/process.

In expand_, post is computed unconditionally at the top of the function, before the early-return branches that don't use it:

const post = m.post.length ? expand_(m.post, max, false) : [''];   // always recurses
  ...
if (!isSequence && !isOptions) {
  if (m.post.match(/,(?!,).*\}/)) {
    str = m.pre + '{' + m.body + escClose + m.post;
    return expand_(str, max, true); // restart — `post` discarded
  }
  return [str];
}

For input like a{},{},…, the first {} is non-expanding, so control reaches the {a},b} rewrite branch - but expand_ has already recursed into post over the entire remaining tail, only to throw the result away.
Each level therefore spawns two recursive expansions over essentially the same remaining work: T(n) = 2·T(n−1) ⇒ O(2ⁿ).

The max option does not mitigate this: max only bounds the output-building loops; neither the post recursion nor the rewrite recursion consults it.

Measured on 5.0.6:

groups (n) input bytes time
20 60 130 ms
24 72 1.9 s
26 78 7.8 s
30 (PoC) 90 ~2 min
Proof of concept
const { expand } = require('brace-expansion');
// 30 non-expanding groups, ~90 bytes — blocks for minutes:
expand('a{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}');
Impact

Any application that passes attacker-influenced strings to brace-expansion.expand() - directly or transitively via minimatch/glob brace patterns - can be driven into a multi-minute-to-indefinite CPU hang by a tiny request, denying service on that thread/process.

Remediation

Upgrade to a patched release. The fix:

  1. Defers computing post until after the early-return branches (and computes it locally in the $-suffix branch), so post is only expanded when a brace set actually expands and the value is used. This alone removes the exponential.
  2. Converts the {a},b} rewrite from recursion to an in-function loop, so a long run of rewrites cannot grow the call stack.

Verified: the PoC drops from ~2 min to 0.55 ms, 5,000 groups complete in ~344 ms, and output is identical to 5.0.6 across a behavioral-equivalence suite (sequences, padding, $-prefix, a{},b}c, {},a}b, x{{a,b}}y, etc.). Post-fix complexity is ~O(n²) on this input class - acceptable for the security fix; a linear rewrite can be a non-urgent follow-up.

If immediate upgrade isn't possible, avoid passing untrusted input to expand() / glob brace patterns, or run such expansion under a timeout/worker.

Severity

  • CVSS Score: 7.7 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:P/S:N/AU:Y/R:U/V:D/RE:M/U:Amber

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

juliangruber/brace-expansion (brace-expansion)

v5.0.7

Compare Source


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added dependencies Pull requests that update a dependency file security labels Jul 21, 2026
@renovate
renovate Bot requested a review from ajasnosz July 21, 2026 15:00
@renovate
renovate Bot force-pushed the renovate/npm-brace-expansion-vulnerability branch from 4d35c05 to 2705286 Compare July 24, 2026 22:38
@renovate
renovate Bot force-pushed the renovate/npm-brace-expansion-vulnerability branch from 2705286 to 41c4a7e Compare July 30, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants