从一个SchemaName到远程代码execution:深挖n8n自动化平台的致命“原型链”

admin 2026-08-23 04:59:59 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: n8n自动化平台存在高危漏洞CVE-2026-33696(CVSS9.4),源于GSuiteAdmin节点未对用户输入的schemaName进行过滤,导致原型链污染。攻击者可通过构造HTTP请求将恶意属性注入Object.prototype,进而利用Git节点触发的simple-git库读取被污染的GITSSHCOMMAND环境变量,实现远程代码执行。该漏洞还可通过污染TypeORM的查询条件导致拒绝服务。修复方案是对用户输入进行黑名单校验或使用Object.create(null)创建无原型对象。 综合评分: 90 文章分类: 漏洞分析,WEB安全,红队,安全开发,恶意软件


cover_image

从一个 Schema Name 到远程代码 execution:深挖 n8n 自动化平台的致命“原型链”

Ots安全

2026年8月17日 19:07 广东

在小说阅读器读本章

去阅读

威胁简报

恶意软件

漏洞攻击

在自动化工作流领域,n8n 凭借其灵活的节点设计和强大的扩展能力,受到了广大开发者和企业的青睐。然而,正因为其处理的数据流极其复杂,任何一处对用户输入的轻信,都可能演变成灾难性的安全漏洞。安全研究员 Simon Köck 近期披露了一则关于 n8n 的高危漏洞(CVE-2026-33696,CVSS 评分高达 9.4),攻击者只需精心构造一个简单的 HTTP 请求,便能在一台自托管或云端的 n8n 实例上实现完全的代码执行(RCE)。

这个漏洞的精妙之处在于,它完美展示了现代 JavaScript 应用中“原型链污染(Prototype Pollution)”如何一步步跨越边界,最终联动其他节点的 Gadget(小工具/跳板),将一个看似无害的字段名变成了系统的控制权。

从一行直觉的代码说起

漏洞的寻路过程往往始于对常见代码模式的审视。在审计 n8n 的内置节点实现时,研究员将目光锁定在了那些“把用户输入的字符串直接当作普通对象键名(Property Key)”的地方。如果这种赋值操作没有对 proto、constructor 或 prototype 进行防御性过滤,那么原型链污染的温床便诞生了。

在检查 nodes-base 库时,GSuiteAdmin 节点很快露出了马脚。这个节点包含一个“Custom Fields”功能,允许用户在创建或更新操作时自定义架构名(Schema Name)、字段名和对应的值。由于这些参数直接来源于工作流配置,任何拥有工作流编辑权限的攻击者都可以对其进行完全控制。

问题的核心代码异常简洁:

constcustomSchemas: IDataObject = {};customFields.forEach((field) => {    const { schemaName, fieldName, value } = field;    customSchemas[schemaName] ??= {};    (customSchemas[schemaName] asIDataObject)[fieldName] = value;});

初看这段代码似乎没有什么问题:它通过 schemaName 对字段进行分组,然后把键值对写入对应的对象中。但如果攻击者将 schemaName 传入 “proto”,逻辑就会发生剧烈的变化。

当执行 customSchemas[“proto”] 时,JavaScript 的原型链机制被触发,返回了全局的 Object.prototype。由于它不是空值,随后的 ??= 赋值直接被跳过;然而紧接着的这一行:(Object.prototype)[fieldName] = value;

这就彻底失控了。攻击者成功将一个受控的属性和值直接写入了全局的 Object.prototype 中。这意味着,在此之后由该 Node.js 进程创建的所有普通对象,都会无条件地继承这个被污染的属性。

巧妙的 Gadget 链:从污染走向 RCE

单纯的原型链污染往往只会导致一些诡异的逻辑错误,但如果配合得当,它就能变成致命的武器。在这里,研究员找到了一条通往 RCE 的完美 Gadget 链,而它的跳板恰好是 n8n 的 Git 节点。

整个攻击链路可以浓缩为:Webhook 触发 → GSuiteAdmin 节点污染原型 → Git 节点执行克隆 → RCE。

当工作流中的 Git 节点被调用时,底层的 simple-git 库会创建一个干净的空环境对象 {} 来存放环境变量。由于这个对象继承自被污染的 Object.prototype,它意外地继承了攻击者预先注入的属性。

当 Node.js 的 spawn() 函数启动子进程来执行 git clone 时,它会遍历环境变量对象。此时,被污染的 GIT_SSH_COMMAND 属性堂而皇之地混入了子进程的环境中。Git 客户端在处理 SSH 类型的远程仓库 URL 时,会严格遵守 GIT_SSH_COMMAND 环境变量,并将其作为终端命令执行。

攻击者在构造请求时,只需要发送如下 Payload:

{  ”schemaName”: ”__proto__”,  ”fieldName”: ”GIT_SSH_COMMAND”,  ”value”: ”sh -c 'id; cat /etc/passwd' --”}

即使前方的 GSuiteAdmin 节点因为调用 Google API 失败而报错,原型链污染的副作用也已经永久生效。紧接着执行的 Git 节点会直接触发带有恶意命令的 GIT_SSH_COMMAND,以当前 n8n 进程用户的身份在宿主机上执行任意指令。

意料之外的破坏:静默的拒绝服务

除了直接的远程代码执行外,这个漏洞在没有 RCE 链的情况下也具备极强的破坏力。在原型被污染后,n8n 底层所依赖的 ORM 框架 TypeORM 在执行数据库查询时,其内部的 buildWhere 函数会通过 for…in 循环遍历对象属性。

这些被意外引入的污染属性会被 TypeORM 误认为合法的数据库查询条件,从而在每一次数据库交互时都抛出 EntityPropertyNotFoundError 异常。这会导致整个 n8n 的 Web 界面瞬间陷入瘫痪,所有正在运行的工作流全部崩溃,实例唯有通过完全重启才能恢复。

修复与启示

这个漏洞的修复方案其实非常直观:在将任何外部输入的字符串用作对象键名之前,必须进行严格的黑名单校验(如拦截 proto、constructor 和 prototype),或者直接使用安全的无原型对象 Object.create(null) 来存储动态数据。实际上,n8n 的代码库中原本就包含带有原型链防护的 deepMerge 工具函数,只是 GSuiteAdmin 节点在实现时遗漏了这一安全边界。

对于开发者而言,这起事件再次敲响了警钟:在动态语言的复杂生态中,对用户输入的信任应当被视为一种潜在的系统威胁。而对于安全从业人员来说,挖掘漏洞的魅力往往就在于将看似微不足道的逻辑缺陷,通过精巧的链条组合,最终推演成直达内核的钥匙。

参考文献

https://simonkoeck.com/writeups/n8n-gsuiteadmin-prototype-pollution-rce

END

公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址

排版 编辑 | Ots 小安

采集 翻译 | Ots Ai牛马

公众号 | AnQuan7 (Ots安全)


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Ots安全 《从一个 Schema Name 到远程代码 execution:深挖 n8n 自动化平台的致命“原型链”》

评论:0   参与:  0