1.1、漏洞成因
该漏洞是由于在OpenClaw Gateway 的 WebSocket 连接处理路径中。当使用 shared-token 或密码认证的后端连接建立时,系统允许客户端自行声明授权范围(scopes),而未在服务端对这些声明进行有效性绑定或验证。攻击者可通过声明提升的权限范围(如 operator.admin)绕过授权边界,获得执行管理员级别网关操作的能力,包括用户管理、策略修改、审计日志操作和系统配置变更等。
正常情况下,高权限 Scopes(如 operator.admin)应仅绑定到经过设备身份验证的连接或显式信任的 Control UI 路径。然而,该漏洞允许共享密钥认证的客户端在不具备设备身份的情况下,直接声明并获得这些提升权限,从而导致漏洞产生。
1.2、漏洞分析
根据通告可以分析出漏洞的本质就是攻击者拿到share token之后在ws的连接过程中声明operator.admin就可以把自己提升到管理员权限。
所以来看看详细Scope机制,在src\gateway\method-scopes.ts中可以看到有5种Scope类型,分别是:
operator.adminoperator.readoperator.writeoperator.approvalsoperator.pairing

而在该文件的32行~133行声明了每个不同类型Scope的职能

权限层级如下:
operator.admin (最高)
↓ 包含
operator.write
↓ 包含
operator.read (最低)
operator.approvals (独立)
operator.pairing (独立)
同时在该文件191行~209行authorizeOperatorScopesForMethod函数中做了鉴权机制的判断,大概就是当用户调用任意method时程序要获取用户的scope,查看用户的scope中是否存在对应方法,如果存在则return True,否则拒绝

到此处已经大致了解Scope的大致内容与职能鉴权判断。那么攻击者该如何传入Scope呢,看一下程序认证机制。
在src\gateway\auth.ts中23行~29行可以看到程序提供了两种认证方式,包括:Shared Auth与Device Auth,其中Shared Auth包含password与token两种凭证,Device Auth则是引入了设备私钥与配对两种凭证。

到auth.ts下面448行~485行可以看到token与password的具体认证实现

首先查看服务端是否有token?用户是否提供了token?调用safeEqualSecret判断服务端与用户传入token的sha-256值是否一致?

在程序的40行~49行的GatewayAuthResult可以看到里面有对 认证成功与否、认证方式、用户身份、是否被限速、重试等待时间的界定。

同时在该文件中还有一个authorizeGatewayConnect函数用于速率限制,不过对于分析漏洞无用不做过多赘述。
接下来看攻击者如何连接以声明自己的虚假身份从而绕过鉴权机制,在src\gateway\protocol\schema\frames.ts的ConnectParamsSchema中定义了ws传输过程中用户应该提供什么参数,包括device、auth、scopes等等

其中device要说一下,在上图的device中可以看到此参数是使用了非常严格的加密,所以攻击者是不能在没有私钥的情况下去进行伪造的。
当攻击者无法传入有效device时,会触发src\gateway\server\ws-connection\message-handler.ts中的handleMissingDeviceIdentity()函数,接着触发clearUnboundScopes()进行Scope回收
在src\gateway\server\ws-connection\message-handler.ts的clearUnboundScopes()函数中可以看到,此处必须全部满足三个条件,Scope才会会被置空,条件分别是:用户声明了自己的身份、未处于 Control UI 的 dangerouslyDisableDeviceAuth 模式并且用户shared认证失败。但是由于攻击者有token,所以Scope不会被清除,也就达到了触发漏洞的目的。

这里的dangerouslyDisableDeviceAuth可以简单说一下,该参数在配置项中默认为false,当该参数为True时程序将忽略device参数,相当于开发者告知用户:
警告:开启此选项将禁用设备身份验证,你自己在承担安全风险
接着,用户自己开启了无视风险继续访问

原本开发者此处代码的意图是避免未知用户随意声明自己身份而做的限制,但开发者错误地将有token与管理员画了等号,最终导致漏洞产生。
漏洞路径:
攻击者获得 shared token (如环境变量 OPENCLAW_GATEWAY_TOKEN 泄露)
|
v
建立 WebSocket 连接
|
v
发送 connect 请求:
{
auth: { token: "leaked_token" }, // 有效的 shared token
device: undefined, // 不提供设备身份
scopes: ["operator.admin"], // 自声明管理员权限
role: "operator"
}
|
v
服务端处理流程:
1. authorizeWsControlUiGatewayConnect() → token 验证成功
2. sharedAuthResult.ok = true → sharedAuthOk = true
3. device = null (攻击者未提供)
4. clearUnboundScopes() 被调用:
- 条件: scopes.length > 0 && !allowBypass && !sharedAuthOk
- sharedAuthOk = true,条件不满足
- scopes 不被清除
1. evaluateMissingDeviceIdentity() 检查:
- roleCanSkipDeviceIdentity("operator", true) 返回 true
- decision.kind = "allow"
|
v
攻击者获得 operator.admin 权限,无需设备身份验证
漏洞验证截图:

1.3、Commit分析
- 当用户声明身份且有
device时,程序会接收传递的Scope参数 - 当缺少
device时,程序会判断当前程序如果是Control UI连接且evaluateMissingDeviceIdentity()返回allow,则程序会接收传递的Scope参数(合法的无设备场景,如开启了dangerouslyDisableDeviceAuth或本地连接) - 当用户没有
device且系统不处于"特殊模式"下时,清除
所以在修复版本的代码中,开发者改变了此处鉴权的侧重点,更倾向于使用device来保证用户的安全性
