从一个 Schema 名到 RCE:n8n 原型污染漏洞(CVE-2026-33696)分析
Ots安全
2026年9月30日 20:31
广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
威胁简报
恶意软件
漏洞攻击
引子
一个自动化工作流平台,最危险的地方往往不是某个复杂的 0day,而是把用户随手填的一串字符串,直接当成了对象的属性名。n8n 的 GSuiteAdmin 节点就栽在这件事上:攻击者只要在\"自定义字段\"里把 schema 名写成 __proto__,就能把任意字符串写进 JavaScript 的全局对象原型,进而借助一个下游的 Git 节点,把\"原型污染\"升级成\"远程代码执行\"。
更刺眼的是:这条链只需要一个能编辑工作流的账号,一次 HTTP 请求,就能以 n8n 进程用户的身份执行命令——而 n8n 进程手里,握着实例里所有凭据的加密密钥。也就是说,这里的 RCE 不是一块落脚点,而是一整串钥匙环。
一、漏洞速览
| 项目 | 内容 |
|---|---|
| CVE 编号 | CVE-2026-33696 |
| GitHub 公告 | GHSA-mxrg-77hm-89hv |
| 漏洞类型 | CWE-1321 对象原型属性可控修改(Prototype Pollution) |
| CVSS | v4.0 9.4(Critical);v3.1 8.8(High) |
| 受影响组件 | n8n 的 GSuiteAdmin 节点与 XML 节点(公告同时覆盖两者) |
| 影响版本 | < 1.123.27;2.0.0-rc.0 起至 < 2.13.3;以及 2.14.0 |
| 修复版本 | 1.123.27 / 2.13.3 / 2.14.1 |
| 利用前提 | 已认证、具备创建工作流/修改工作流权限的用户 |
| 攻击向量 | 网络(AV:N);复杂度低;所需权限低;无需用户交互 |
二、作者是怎么挖到的:一个朴素的方法论
Simon Koeck 在审计 n8n 的节点实现时,给自己定了一条很简单的检索规则:凡是有\"用户提供的字符串,被当作普通对象的属性键、且未先检查 __proto__ / constructor / prototype\"的地方,都值得看一眼。
他在 n8n-nodes-base 包里 grep 这类模式,GSuiteAdmin 节点立刻\"脱颖而出\"。该节点的\"自定义字段(Custom Fields)\"在创建/更新用户时,允许用户配置 schema 名(schemaName)、字段名(fieldName)、值(value)——这三个字段全部来自工作流配置,也就是说,任何能编辑工作流的攻击者都能完全控制它们。
三、漏洞根因:把用户输入当对象键
GSuiteAdmin 节点在用户创建(约第 520–521 行)与更新(约第 802–803 行)操作中,用了完全相同的一段代码来处理自定义 schema 字段:
const customSchemas: IDataObject = {};customFields.forEach((field) => { const { schemaName, fieldName, value } = field as { schemaName: string; fieldName: string; value: string; };
customSchemas[schemaName] ??= {}; // (1) (customSchemas[schemaName] as IDataObject)[fieldName] = value; // (2)});
整个 bug 就藏在这两行。当 schemaName 是 \"__proto__\" 时:
customSchemas[\"__proto__\"]
会触发 __proto__ 的 getter,返回 Object.prototype。它不是 nullish,于是 ??= 的赋值成了空操作;
2. (Object.prototype)[fieldName] = value
把攻击者可控的字符串直接写到了全局对象原型上。
此后创建的每一个普通对象,都会继承这个被污染的属性。
四、从污染到 RCE 的利用链
光是污染本身就已经够糟(它会通过 TypeORM 把整个 n8n 实例打崩,详见第六节),但它还能借由作者此前在 XML 节点报告里发现的同一个 gadget,升级成完整的 RCE。链路是这样串起来的:
- simple-git 创建普通 env 对象
:当 Git 节点调用 .env() 时,simple-git 会分配一个 {} 来装环境变量,这个对象继承自 Object.prototype;
2. Node.js 的 spawn() 会继承被污染的属性
:在构造子进程环境时,Node 会遍历 env 对象的属性——包括从被污染原型上继承来的那些;
3. git 尊重 GIT_SSH_COMMAND
:当 git 遇到一个 SSH 风格的 URL,它会把 GIT_SSH_COMMAND 当作 shell 命令来启动。如果我们污染了 Object.prototype.GIT_SSH_COMMAND,它就会一路传导进 git 子进程并执行。
所以完整的攻击就是:Webhook → GSuiteAdmin(污染)→ Git(RCE)。
五、PoC 逻辑骨架(公开披露的复现思路)
原文的复现工作流由三个节点组成:
- Webhook 节点
:监听 POST /rce;
* GSuiteAdmin 节点
:资源选 User、操作选 Create,把自定义字段的 schema 名、字段名、值都设为从 Webhook 请求体读取的表达式;
* Git 节点
:操作选 Clone,指向一个 SSH 风格的 URL。
原文披露的那一关键请求,其核心是把三个字段分别设为:
{ \"schemaName\":\"__proto__\", \"fieldName\":\"GIT_SSH_COMMAND\", \"value\":\"<攻击者期望执行的命令>\"}
说明(合规边界):按照原文披露的技术事实,上述三个键名(
__proto__、GIT_SSH_COMMAND)与触发逻辑是该漏洞利用的核心,予以保留;但不直接粘贴可一键执行的恶意命令载荷。GSuiteAdmin 节点会在真正发起 Google API 调用时才失败——而此时污染早已发生,所以执行日志里看到一个\"失败的 GSuiteAdmin 节点\"并不等于攻击没成功。随后 Git 节点以被污染的GIT_SSH_COMMAND执行git clone,命令以 n8n 进程用户的身份落地。
六、附带的 DoS 副作用
即便不接 Git 这条 RCE 链,污染本身也具备破坏性。在 Object.prototype 被写入杂质属性之后,TypeORM 的 buildWhere 函数会通过 for...in 遍历把那些继承来的额外属性也一并收进去,于是在每一条数据库查询上都抛出 EntityPropertyNotFoundError:
结果就是 n8n 后台界面卡死、所有工作流执行失败,实例必须完整重启才能恢复。换句话说,一个手法笨拙的攻击者,甚至能\"顺手\"把你整座平台搞瘫。
七、影响范围
- 远程代码执行
:以 n8n 进程用户身份,在所有部署形态(自托管、worker 模式、Cloud)上均可触发;
* 凭据全面失窃
:n8n 进程持有实例内所有已存凭据的加密密钥;
* 拒绝服务(DoS)
:TypeORM 的崩溃循环让实例在重启前完全不可用。
八、修复与防御(含本文增补的运维要点)
官方的修复思路很直接:在把用户字符串当作对象键之前,先拒绝危险的属性名。对 schemaName 做一份针对 __proto__ / constructor / prototype 的黑名单检查,或者直接把 customSchemas 改成 Object.create(null),就能从根上堵住污染。n8n 代码库里其实已经有一个带原型污染防护的 deepMerge 工具函数,只是 GSuiteAdmin 节点此前没用上它。
以下为本文在原文基础上的原创增量(结合第三方分析):
- 版本陷阱:
2.14.0仍然漏洞。
修复版本是 2.14.1 / 2.13.3 / 1.123.27——\"我们跑的是 2.14 系列\"并不能证明安全,务必核对具体版本字符串。
2. 公告同时覆盖 XML 节点,但多数文章只提 GSuiteAdmin。
厂商给出的临时缓解 NODES_EXCLUDE=n8n-nodes-base.xml 只禁用了 XML 节点,GSuiteAdmin 仍然可达,因此该缓解只是权宜之计,并未触及根本。
3. 补丁落地后必须重启。
包更新不会自动清除一个已经在运行中进程里被污染的对象原型,重启前污染一直有效。
4. 最小化编辑权限。
在无法立即升级时,把\"创建工作流/修改工作流\"的权限只开放给完全可信的用户。
5. 实例内痕迹排查(第三方给出的思路)。
工作流定义持久化在数据库中,一次尝试会留下痕迹,可针对 workflow_entity 表里 nodes 字段包含 __proto__ / constructor / prototype 的记录做检索(Postgres 与 SQLite 的表名/字段名需自行适配;其中 constructor 命中会较\"吵\",需结合上下文判断)。
参考地址
- 原文(Simon Koeck):https://simonkoeck.com/writeups/n8n-gsuiteadmin-prototype-pollution-rce
- GitHub Security Advisory GHSA-mxrg-77hm-89hv:https://github.com/advisories/GHSA-mxrg-77hm-89hv
- NVD CVE-2026-33696:https://nvd.nist.gov/vuln/detail/CVE-2026-33696
- n8n 官方安全公告:https://github.com/n8n-io/n8n/security/advisories/GHSA-mxrg-77hm-89hv
- 第三方解读(DEV Community,含 XML 节点/2.14.0/重启/SQL 排查):https://dev.to/secbyjasonmiller/one-proto-away-from-losing-every-credential-in-your-n8n-instance-1m5p
- 同文转载(worldprogramming.org):https://www.worldprogramming.org/posts/cve-2026-33696-from-a-schema-name-to-rce-in-n8n-miyg96
参考资料:CVE-2026-33696 / GHSA-mxrg-77hm-89hv 官方公告;NVD 条目;Simon Koeck 原文;社区二次分析。
END
公众号内容都来自国外等平台- 搜索的内容通过结合编写 -
公众号 | AnQuan7 (Ots安全)
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论