🎯 CVE-2026-8161 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹
CVE-2026-8161 深度技术分析
摘要:CVE-2026-8161 是 PillarJS multiparty 库在 4.2.3 及更低版本中存在的高危拒绝服务(DoS)漏洞,CVSS 评分为 7.5。攻击者通过构造包含与 Object.prototype 继承属性(如 __proto__、constructor、toString)同名的 multipart/form-data 字段,可使解析器在原型链值上调用 .push(),触发 TypeError 异常并因未捕获而崩溃进程。升级到 multiparty@4.3.0 及以上版本即可修复,官方确认无有效缓解措施。
📌 漏洞概述
CVE 编号:CVE-2026-8161
CVSS 评分:7.5(高危)
影响产品:pillarjs/multiparty
影响版本:multiparty@4.2.3 及以下所有版本
漏洞类型:未捕获异常导致的拒绝服务(CWE-248 Uncaught Exception / CWE-1321 原型污染相关的不安全属性访问)
multiparty 是一个广泛使用的 Node.js multipart/form-data 解析库,常用于处理文件上传和表单提交。该漏洞允许远程攻击者不经过任何前置认证,仅通过构造一个特殊的 HTTP 请求,即可使目标服务的 Node.js 进程抛出未捕获异常并直接崩溃,造成服务不可用。由于攻击向量简单且可在公网直接发送,该漏洞的实际利用门槛非常低。
🔬 漏洞根因分析
漏洞的根本原因在于 multiparty 内部使用普通 JavaScript 对象(Plain Object)作为字段与文件的存储容器,但在访问这些容器时直接使用了 obj[name] 形式的属性读取,而没有区分“对象自身拥有的属性”与“原型链继承的属性”。
在 Node.js 中,普通对象默认继承自 Object.prototype,因此可以通过原型链访问到一系列内建属性,例如 __proto__、constructor、toString、hasOwnProperty 等。当攻击者构造一个字段名恰为这些名称之一时,例如 __proto__,那么表达式 fields[name] 将不再返回 undefined(因为对象本身没有该属性),而是返回 Object.prototype 这个对象本身。该值显然是“真值”(truthy),所以原有代码中的“若不存在则初始化数组”的逻辑会被绕过:
var fieldsArray = fields[name] || (fields[name] = [])
fieldsArray.push(value)此时 fieldsArray 实际上指向 Object.prototype,而不是一个数组。随后代码调用 fieldsArray.push(value),但 Object.prototype 并没有 push 方法(push 是 Array.prototype 的方法),因此 JavaScript 运行时抛出 TypeError: fieldsArray.push is not a function。
更关键的是,这个异常发生在 multiparty 的异步解析流程内部。multiparty 基于 stream 和回调机制工作,很多解析回调是在异步上下文中触发的。如果库内部没有为这些回调统一捕获异常,那么 TypeError 会沿着事件循环直接向上冒泡,最终导致进程级未捕获异常。Node.js 默认对未捕获异常的处理是打印堆栈并退出进程,从而造成拒绝服务。
官方补丁的修复思路正是从“仅信任自有属性”出发。修复后的代码先通过 Object.prototype.hasOwnProperty.call(files, name) 判断字段名是否为对象自身拥有的属性,只有自身属性才允许读取;然后进一步使用 Array.isArray() 确认当前值确实是数组才执行 push,否则一律重新初始化为新数组:
var filesArray = Object.prototype.hasOwnProperty.call(files, name)
? files[name]
: undefined
if (Array.isArray(filesArray)) {
filesArray.push(file)
} else {
files[name] = [file]
}这种双重检查既能拦截原型链属性的干扰,又能确保存储值始终为合法数组,从根因上消除了类型混淆。
💥 影响与危害
任何使用 multiparty 且版本 ≤ 4.2.3 的 Node.js 服务,只要对外开放了基于 multipart/form-data 的上传接口(如文件上传、表单提交、REST API 等),都直接受此漏洞影响。攻击者无需任何权限,只需发送一个简单构造的 HTTP 请求即可触发崩溃。具体危害体现在:
- 远程拒绝服务:攻击者可反复发送恶意请求,使服务进程频繁崩溃,严重影响业务可用性,甚至导致整个实例反复重启。
- 攻击成本极低:利用请求只需包含一个字段名为
__proto__(或constructor、toString)的 multipart 数据,无需特殊工具,使用 curl 或各种脚本即可完成。 - 潜在级联影响:在微服务或负载均衡环境中,单个实例崩溃后流量会转移到其他实例,可能引发雪崩效应;同时崩溃导致的连接中断可能破坏上游调用方的请求状态。
- 缺乏公开 EXP 但 PoC 已存在:虽然 Exploit-DB 暂无公开 exploit 代码,但 GitHub 上已出现概念验证(PoC)仓库(Ser0n-ath/multiparty-CVE-2026-8161),攻击者可轻易参考验证,实际利用风险正在快速上升。
该漏洞尚未被列入 CISA KEV(已知被利用漏洞目录),但这不意味风险可以忽略;考虑到 multiparty 是历史悠久的 npm 库,存量部署数量大,真实攻击可能在补丁普及前随时发生。
🛡️ 修复与缓解
官方修复:
- 立即升级到 multiparty@4.3.0 或更高版本。官方已在 4.3.0 中采用
hasOwnProperty+Array.isArray双重校验,彻底解决了原型链属性访问引发的类型错误。 - 官方明确指出:没有有效的缓解措施(Workarounds: none),因此升级是唯一可靠的修复方式。
补充性缓解建议(不能替代升级):
- 在网关或反向代理层拦截字段名包含
__proto__、constructor、prototype等敏感字符串的 multipart 请求,作为临时过渡手段。 - 使用进程守护工具(如 PM2、systemd)设置自动重启,降低单个请求导致长期不可用的影响,但这并不能阻止攻击者反复触发崩溃。
- 监控应用日志中的
TypeError、hasOwnProperty相关异常以及进程异常退出事件,及时感知攻击行为。 - 在代码层面对 multipart 解析结果进行边界性验证,避免将用户可控字段名直接用于对象属性访问,推荐使用
Map或专门的字段白名单机制。
总而言之,CVE-2026-8161 是一个触发条件简单、影响面广的拒绝服务漏洞。所有依赖 multiparty 且版本低于 4.3.0 的项目应视为潜在易受攻击状态,必须尽快安排升级,并同步检查应用兼容性,防止因库行为变化导致业务逻辑异常。
🧪 PoC 复现
从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。
📋 代码元数据语言md来源Ser0n-ath/multiparty-CVE-2026-8161针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明
# CVE-2026-8161
Proof of concept of CVE-2026-8161 (Multiparty)
# Description
`multiparty@4.2.3` and earlier are vulnerable to denial of service through an uncaught exception.
The parser stores uploaded fields and files in plain JavaScript objects and does not safely distinguish parser owned keys from inherited object properties. A crafted multipart field name can cause the parser to read unexpected prototype-chain values and crash while handling the upload.
Any service that accepts multipart uploads through vulnerable versions of multiparty may be affected.
# How it works
The issue happens because `fields` and `files` are plain JavaScript objects,
but they are used like safe key-value maps for user-controlled names.
```js
var fieldsArray = fields[name] ||(fields[name] = [])
fieldsArray.push(value)
var filesArray = files[name] ||(files[name] = [])
filesArray.push(file)
```
The issue is that `fields[name]` and `files[name]` use normal JavaScript property lookup. For plain objects,
that lookup can return inherited properties from the prototype chain instead of only values stored on the object itself.
When name is `__proto__`,JavaScript can resolve it through the prototype chain and return the inherited prototype object instead of undefined. Since that value is truthy,
the fallback assignment is skipped and the parser never creates a real array for that field.
The patch fixes this by only trusting keys that belong directly to the object:
```js
var filesArray = Object.prototype.hasOwnProperty.call(files,name)
? files[name]
: undefined
```
Then the parser appends only when the stored value is actually an array,
otherwise it initializes a fresh one:
```js
if (Array.isArray(filesArray)) {filesArray.push(file)
}else {files[name] = [file]
}```
When .push() is called on a value that is not an array,it throws a TypeError. Because this happens inside Multiparty’s async parsing flow,normal caller-side error handling may not catch it,
allowing the exception to crash the process.
# Timeline
- 2026-01-12: Vulnerability reported to the multiparty maintainers.
- 2026-01-17: Report accepted,remediation work began.
- 2026-02-14: Coordinated review started with @pillarjs/security-triage.
- 2026-02-16: Patch discussions ->
`Object.prototype.hasOwnProperty.call(...)`.
- 2026-03-29: Advisory title and metadata updated to reflect denial-of-service impact.
- 2026-04: Remediation approach reviewed and approved.
- 2026-05-08: Advisory finalized and CVE-2026-8161 reserved.
- 2026-05-11: Fix merged into pillarjs:master.
<br>
# Demo Usage
Run the mocklab environment and send the test payload to both targets:
```
docker compose up -d
python3 secdos.py -u http://localhost:8080/api/submit
python3 secdos.py -u http://localhost:8081/api/submit
```
The vulnerable target will crash and return `[PASS]`. The patched target will handle the request safely and return `[FAIL]`.
>If re-running against the vulnerable server,
restart it first
# Setup overview
### Vulnerable Server
- Access on localhost:8080
- Nginx server acting as reverse proxy,on failure it displays error page with status 502
- Nginx resolves vuln server address by service name
- Uses multiparty 4.2.3 (vulnerable)
### Patched Server
- Running &
Accessed on localhost:8081
- Nginx not required
- Uses multiparty 4.3.0 (patched)
Building a patched image from dockerfile requires a build arg `PATCHED=1`
## References
https://github.com/pillarjs/multiparty/security/advisories/GHSA-qxch-whhj-8956
https://github.com/pillarjs/multiparty/commit/8ee6aca09aca29e923da48da8260c87aa964b282⚔️ EXP 利用代码
截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。
🕵️ 检测指纹
当前规则库未收录针对该 CVE 的专用检测规则。建议:
- 根据漏洞根因编写 Nuclei 检测模板
- 在 WAF/IDS 中配置针对漏洞特征的规则
- 关注漏洞指纹库更新
🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-11 09:06 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库