The maxLength mitigation added in 5.0.8 for GHSA-mh99-v99m-4gvg / CVE-2026-14257 is incomplete. It bounds the accumulator where results are combined, but not the intermediate arrays that feed it. A ~25 KB input still crashes the Node process with an uncatchable out-of-memory error, so try/catch around expand() does not help. A second, related path in the same function lets a ~400 KB input block the event loop for over two minutes …
expand() bounds the number of results it produces (the max option, 100_000 by default) but not their length. By chaining many brace groups, an attacker keeps the result count under max while making every result grow with the number of groups. Building max long results — plus the intermediate arrays combined at each brace group — exhausts memory and crashes the Node process with an uncatchable out-of-memory error. try/catch around …
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 …
The max option was being applied too late: When expanding a single large numeric range like {1..10000000}, the sequence generation loop generates all 10 million intermediate elements before the max limit is applied With max=10, the output is correctly limited to 10 items, but the process still allocates ~505 MB and spends ~800ms building the full intermediate array.
A brace pattern with a zero step value (e.g., {1..2..0}) causes the sequence generation loop to run indefinitely, making the process hang for seconds and allocate heaps of memory. The loop in question: https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L184 test() is one of https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L107-L113 The increment is computed as Math.abs(0) = 0, so the loop variable never advances. On a test machine, the process hangs for about 3.5 seconds and allocates roughly 1.9 GB of …