diff --git a/docs/zh-CN/gateway/protocol.md b/docs/zh-CN/gateway/protocol.md index 5fee5fd71..e4e275c7f 100644 --- a/docs/zh-CN/gateway/protocol.md +++ b/docs/zh-CN/gateway/protocol.md @@ -2,29 +2,29 @@ read_when: - 实现或更新 Gateway 网关 WS 客户端 - 调试协议不匹配或连接失败 - - 重新生成协议 schema / 模型 + - 重新生成协议 schema/模型 summary: Gateway 网关 WebSocket 协议:握手、帧、版本控制 title: Gateway 网关协议 x-i18n: - generated_at: "2026-04-24T18:08:44Z" + generated_at: "2026-04-25T22:27:13Z" model: gpt-5.4 provider: openai - source_hash: 03f729a1ee755cdd8a8dd1fef5ae1cb0111ec16818bd9080acd2ab0ca2dbc677 + source_hash: a2411ebd50a883028e2d8e88a4a79e4c1350cefd37a12f293de9686e3bc067ea source_path: gateway/protocol.md workflow: 15 --- -Gateway 网关 WS 协议是 OpenClaw 的**单一控制平面 + 节点传输协议**。所有客户端(CLI、web UI、macOS 应用、iOS/Android 节点、无头节点)都通过 WebSocket 连接,并在握手时声明其**角色** + **作用域**。 +Gateway 网关 WS 协议是 OpenClaw 的**单一控制平面 + 节点传输层**。所有客户端(CLI、web UI、macOS 应用、iOS/Android 节点、无头节点)都通过 WebSocket 连接,并在握手时声明其**角色** + **作用域**。 ## 传输 - WebSocket,带有 JSON 负载的文本帧。 - 第一帧**必须**是一个 `connect` 请求。 -- 连接前帧大小上限为 64 KiB。成功握手后,客户端应遵循 `hello-ok.policy.maxPayload` 和 `hello-ok.policy.maxBufferedBytes` 限制。启用诊断时,过大的入站帧和缓慢的出站缓冲区会先发出 `payload.large` 事件,然后 Gateway 网关才会关闭连接或丢弃受影响的帧。这些事件会保留大小、限制、界面和安全原因码。它们不会保留消息正文、附件内容、原始帧正文、令牌、cookies 或密钥值。 +- 连接前帧的上限为 64 KiB。握手成功后,客户端应遵循 `hello-ok.policy.maxPayload` 和 `hello-ok.policy.maxBufferedBytes` 限制。启用诊断后,过大的入站帧和缓慢的出站缓冲区会在 Gateway 网关关闭连接或丢弃受影响帧之前发出 `payload.large` 事件。这些事件会保留大小、限制、表面以及安全原因代码。它们不会保留消息正文、附件内容、原始帧正文、令牌、Cookie 或秘密值。 ## 握手(connect) -Gateway 网关 → 客户端(连接前挑战): +Gateway 网关 → 客户端(连接前质询): ```json { @@ -91,9 +91,9 @@ Gateway 网关 → 客户端: } ``` -`server`、`features`、`snapshot` 和 `policy` 都是 schema 中的必填项(`src/gateway/protocol/schema/frames.ts`)。`canvasHostUrl` 是可选项。`auth` 会在可用时报告协商后的角色 / 作用域,并在 Gateway 网关签发设备令牌时包含 `deviceToken`。 +`server`、`features`、`snapshot` 和 `policy` 都是 schema(`src/gateway/protocol/schema/frames.ts`)要求的必填项。`canvasHostUrl` 是可选项。`auth` 会在可用时报告协商后的角色/作用域,并在 Gateway 网关签发设备令牌时包含 `deviceToken`。 -当未签发设备令牌时,`hello-ok.auth` 仍可以报告协商后的权限: +未签发设备令牌时,`hello-ok.auth` 仍然可以报告协商后的权限: ```json { @@ -104,7 +104,9 @@ Gateway 网关 → 客户端: } ``` -当签发了设备令牌时,`hello-ok` 还会包含: +受信任的同进程后端客户端(`client.id: "gateway-client"`、`client.mode: "backend"`)在使用共享 Gateway 网关 token/password 通过直接 loopback 连接进行身份验证时,可以省略 `device`。此路径保留用于内部控制平面 RPC,可避免过期的 CLI/设备配对基线阻碍本地后端工作,例如子智能体会话更新。远程客户端、浏览器来源客户端、节点客户端以及显式设备令牌/设备身份客户端仍然使用常规配对和作用域升级检查。 + +签发设备令牌时,`hello-ok` 还会包含: ```json { @@ -116,7 +118,7 @@ Gateway 网关 → 客户端: } ``` -在受信任的 bootstrap 交接过程中,`hello-ok.auth` 还可能在 `deviceTokens` 中包含额外的有界角色条目: +在受信任的引导交接期间,`hello-ok.auth` 还可能在 `deviceTokens` 中包含额外的有界角色条目: ```json { @@ -135,7 +137,7 @@ Gateway 网关 → 客户端: } ``` -对于内置的 node/operator bootstrap 流程,主节点令牌保持为 `scopes: []`,而任何交接的 operator 令牌都保持受限于 bootstrap operator allowlist(`operator.approvals`、`operator.read`、`operator.talk.secrets`、`operator.write`)。Bootstrap 作用域检查仍然保持角色前缀:operator 条目只满足 operator 请求,而非 operator 角色仍然需要其自身角色前缀下的作用域。 +对于内置的 node/operator 引导流程,主 node 令牌保持 `scopes: []`,而任何交接的 operator 令牌都保持受限于引导 operator 允许列表(`operator.approvals`、`operator.read`、`operator.talk.secrets`、`operator.write`)。引导作用域检查保持按角色前缀区分:operator 条目只满足 operator 请求,而非 operator 角色仍然需要其自身角色前缀下的作用域。 ### 节点示例 @@ -178,7 +180,7 @@ Gateway 网关 → 客户端: - **响应**:`{type:"res", id, ok, payload|error}` - **事件**:`{type:"event", event, payload, seq?, stateVersion?}` -有副作用的方法需要 **idempotency keys**(见 schema)。 +具有副作用的方法需要 **idempotency keys**(参见 schema)。 ## 角色 + 作用域 @@ -200,104 +202,104 @@ Gateway 网关 → 客户端: 带有 `includeSecrets: true` 的 `talk.config` 需要 `operator.talk.secrets`(或 `operator.admin`)。 -由插件注册的 Gateway 网关 RPC 方法可以请求其自己的 operator 作用域,但保留的核心管理前缀(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)始终解析为 `operator.admin`。 +由插件注册的 Gateway 网关 RPC 方法可以请求它们自己的 operator 作用域,但保留的核心管理前缀(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)始终解析为 `operator.admin`。 -方法作用域只是第一道关卡。某些通过 `chat.send` 到达的斜杠命令还会额外应用更严格的命令级检查。例如,持久化的 `/config set` 和 `/config unset` 写入需要 `operator.admin`。 +方法作用域只是第一道关卡。某些通过 `chat.send` 到达的斜杠命令会在此基础上应用更严格的命令级检查。例如,持久化的 `/config set` 和 `/config unset` 写入需要 `operator.admin`。 -`node.pair.approve` 也在基础方法作用域之上额外有一个批准时作用域检查: +`node.pair.approve` 在基础方法作用域之上还有额外的审批时作用域检查: - 无命令请求:`operator.pairing` -- 带非 exec 节点命令的请求:`operator.pairing` + `operator.write` +- 带有非 exec 节点命令的请求:`operator.pairing` + `operator.write` - 包含 `system.run`、`system.run.prepare` 或 `system.which` 的请求: `operator.pairing` + `operator.admin` -### caps/commands/permissions(node) +### Caps/commands/permissions(node) 节点在连接时声明能力声明: -- `caps`:高级能力类别。 -- `commands`:用于调用的命令 allowlist。 +- `caps`:高层能力类别。 +- `commands`:用于 invoke 的命令允许列表。 - `permissions`:细粒度开关(例如 `screen.record`、`camera.capture`)。 -Gateway 网关将这些视为**声明**,并在服务器端强制执行 allowlist。 +Gateway 网关将这些视为**声明**,并执行服务端允许列表。 ## 在线状态 - `system-presence` 返回按设备身份键控的条目。 -- 在线状态条目包含 `deviceId`、`roles` 和 `scopes`,这样 UI 即使在同一设备同时以 **operator** 和 **node** 身份连接时,也能显示为单行。 +- 在线状态条目包含 `deviceId`、`roles` 和 `scopes`,因此 UI 即使在设备同时以 **operator** 和 **node** 身份连接时,也能为其显示单独一行。 -## 广播事件作用域 +## 广播事件作用域限制 -服务器推送的 WebSocket 广播事件受作用域控制,因此仅配对作用域或仅节点会话不会被动接收会话内容。 +服务端推送的 WebSocket 广播事件受作用域门控,因此仅具备配对作用域或仅节点的会话不会被动接收会话内容。 - **聊天、智能体和工具结果帧**(包括流式 `agent` 事件和工具调用结果)至少需要 `operator.read`。没有 `operator.read` 的会话会完全跳过这些帧。 -- **插件定义的 `plugin.*` 广播** 会根据插件注册方式受限于 `operator.write` 或 `operator.admin`。 -- **状态和传输事件**(`heartbeat`、`presence`、`tick`、连接 / 断开生命周期等)保持不受限制,以便每个已认证会话都能观察传输健康状态。 -- **未知的广播事件族** 默认受作用域控制(默认拒绝),除非已注册的处理器显式放宽它们。 +- **插件定义的 `plugin.*` 广播** 会根据插件注册方式,门控到 `operator.write` 或 `operator.admin`。 +- **Status 和传输事件**(`heartbeat`、`presence`、`tick`、连接/断开生命周期等)保持不受限制,以便每个已认证会话都能观察传输健康状态。 +- **未知广播事件族** 默认受作用域门控(默认关闭,fail-closed),除非注册的处理程序明确放宽它们。 -每个客户端连接都维护自己的按客户端递增序列号,因此即使不同客户端看到的是经过不同作用域过滤后的事件流子集,广播在该 socket 上仍能保持单调有序。 +每个客户端连接都保留自己的每客户端序列号,因此即使不同客户端看到的事件流子集因作用域过滤而不同,广播在该 socket 上仍保持单调顺序。 ## 常见 RPC 方法族 -公共 WS 表面比上面的握手 / 认证示例更广。这不是生成的导出清单 —— `hello-ok.features.methods` 是从 `src/gateway/server-methods-list.ts` 加载的保守发现列表,并结合已加载的插件 / 渠道方法导出构建而成。请将其视为功能发现,而不是 `src/gateway/server-methods/*.ts` 的完整枚举。 +公共 WS 表面比上面的握手/认证示例更广。这不是生成的导出——`hello-ok.features.methods` 是一个保守的发现列表,基于 `src/gateway/server-methods-list.ts` 加上已加载插件/渠道方法导出构建。应将其视为功能发现,而不是对 `src/gateway/server-methods/*.ts` 的完整枚举。 - - - `health` 返回缓存的或刚探测到的 Gateway 网关健康状态快照。 - - `diagnostics.stability` 返回最近的有界诊断稳定性记录器。它会保留操作元数据,例如事件名称、计数、字节大小、内存读数、队列 / 会话状态、渠道 / 插件名称和会话 id。它不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、令牌、cookies 或密钥值。需要 `operator.read` 作用域。 - - `status` 返回类似 `/status` 的 Gateway 网关摘要;敏感字段仅对具有 admin 作用域的 operator 客户端可见。 - - `gateway.identity.get` 返回 relay 和 pairing 流程使用的 Gateway 网关设备身份。 + + - `health` 返回缓存的或新探测的 Gateway 网关健康快照。 + - `diagnostics.stability` 返回最近的有界诊断稳定性记录器。它会保留操作元数据,例如事件名称、计数、字节大小、内存读数、队列/会话状态、渠道/插件名称以及会话 id。它不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、令牌、Cookie 或秘密值。需要 operator.read 作用域。 + - `status` 返回 `/status` 风格的 Gateway 网关摘要;敏感字段仅包含在具有 admin 作用域的 operator 客户端中。 + - `gateway.identity.get` 返回用于 relay 和配对流程的 Gateway 网关设备身份。 - `system-presence` 返回当前已连接 operator/node 设备的在线状态快照。 - - `system-event` 追加一个系统事件,并可更新 / 广播在线状态上下文。 - - `last-heartbeat` 返回最新持久化的 heartbeat 事件。 - - `set-heartbeats` 切换 Gateway 网关上的 heartbeat 处理。 + - `system-event` 追加一个系统事件,并且可以更新/广播在线状态上下文。 + - `last-heartbeat` 返回最新持久化的心跳事件。 + - `set-heartbeats` 切换 Gateway 网关上的心跳处理。 - + - `models.list` 返回运行时允许的模型目录。 - - `usage.status` 返回提供商用量窗口 / 剩余额度摘要。 - - `usage.cost` 返回某个日期范围内聚合后的成本使用摘要。 + - `usage.status` 返回提供商用量窗口/剩余额度摘要。 + - `usage.cost` 返回某个日期范围的聚合成本用量摘要。 - `doctor.memory.status` 返回活动默认智能体工作区的向量内存 / embedding 就绪状态。 - - `sessions.usage` 返回按会话划分的使用摘要。 - - `sessions.usage.timeseries` 返回单个会话的时间序列使用情况。 - - `sessions.usage.logs` 返回单个会话的使用日志条目。 + - `sessions.usage` 返回每个会话的用量摘要。 + - `sessions.usage.timeseries` 返回单个会话的时序用量。 + - `sessions.usage.logs` 返回单个会话的用量日志条目。 - - - `channels.status` 返回内置 + 内置插件渠道 / 插件状态摘要。 - - `channels.logout` 在某个渠道支持登出时,对指定渠道 / 账号执行登出。 - - `web.login.start` 为当前支持二维码的 web 渠道提供商启动二维码 / web 登录流程。 - - `web.login.wait` 等待该二维码 / web 登录流程完成,并在成功时启动渠道。 - - `push.test` 向已注册的 iOS 节点发送测试 APNs 推送。 + + - `channels.status` 返回内置 + 内置打包渠道/插件的 Status 摘要。 + - `channels.logout` 在渠道支持登出的情况下,登出特定渠道/账户。 + - `web.login.start` 为当前支持 QR/web 登录的 web 渠道提供商启动一个 QR/web 登录流程。 + - `web.login.wait` 等待该 QR/web 登录流程完成,并在成功后启动渠道。 + - `push.test` 向已注册的 iOS 节点发送一个测试 APNs 推送。 - `voicewake.get` 返回已存储的唤醒词触发器。 - - `voicewake.set` 更新唤醒词触发器并广播该变更。 + - `voicewake.set` 更新唤醒词触发器并广播更改。 - - - `send` 是直接的出站投递 RPC,用于在聊天运行器之外按渠道 / 账号 / 线程目标发送消息。 - - `logs.tail` 返回已配置 Gateway 网关文件日志的尾部内容,支持 cursor/limit 和最大字节数控制。 + + - `send` 是聊天运行器之外、针对渠道/账户/线程目标发送的直接出站投递 RPC。 + - `logs.tail` 返回已配置的 Gateway 网关文件日志尾部,支持 cursor/limit 和最大字节控制。 - - - `talk.config` 返回生效的 Talk 配置负载;`includeSecrets` 需要 `operator.talk.secrets`(或 `operator.admin`)。 - - `talk.mode` 为 WebChat / Control UI 客户端设置 / 广播当前 Talk 模式状态。 - - `talk.speak` 通过活动中的 Talk 语音提供商合成语音。 - - `tts.status` 返回 TTS 启用状态、活动提供商、回退提供商和提供商配置状态。 + + - `talk.config` 返回有效的 Talk 配置负载;`includeSecrets` 需要 `operator.talk.secrets`(或 `operator.admin`)。 + - `talk.mode` 为 WebChat/Control UI 客户端设置/广播当前 Talk 模式状态。 + - `talk.speak` 通过活动的 Talk speech 提供商合成语音。 + - `tts.status` 返回 TTS 启用状态、活动提供商、后备提供商以及提供商配置状态。 - `tts.providers` 返回可见的 TTS 提供商清单。 - `tts.enable` 和 `tts.disable` 切换 TTS 偏好状态。 - `tts.setProvider` 更新首选 TTS 提供商。 - - `tts.convert` 执行一次性文本转语音转换。 + - `tts.convert` 运行一次性文本转语音转换。 - - - `secrets.reload` 重新解析活动的 SecretRefs,并且仅在完全成功时替换运行时密钥状态。 - - `secrets.resolve` 为特定命令 / 目标集解析命令目标密钥分配。 + + - `secrets.reload` 重新解析活动 SecretRefs,并且仅在完全成功时替换运行时秘密状态。 + - `secrets.resolve` 为特定命令/目标集合解析面向命令目标的秘密分配。 - `config.get` 返回当前配置快照和哈希值。 - `config.set` 写入经过验证的配置负载。 - `config.patch` 合并部分配置更新。 - `config.apply` 验证并替换完整配置负载。 - - `config.schema` 返回由 Control UI 和 CLI 工具使用的实时配置 schema 负载:schema、`uiHints`、版本和生成元数据,包括运行时可加载时的插件 + 渠道 schema 元数据。该 schema 包含从 UI 使用的相同标签和帮助文本派生出的字段 `title` / `description` 元数据,包括嵌套对象、通配符、数组项,以及在存在匹配字段文档时的 `anyOf` / `oneOf` / `allOf` 组合分支。 - - `config.schema.lookup` 返回单个配置路径的路径范围查询负载:规范化路径、浅层 schema 节点、匹配的 hint + `hintPath`,以及供 UI/CLI 深入查看的直接子项摘要。查询 schema 节点保留面向用户的文档和常见验证字段(`title`、`description`、`type`、`enum`、`const`、`format`、`pattern`、数值 / 字符串 / 数组 / 对象边界,以及如 `additionalProperties`、`deprecated`、`readOnly`、`writeOnly` 之类的标记)。子项摘要公开 `key`、规范化的 `path`、`type`、`required`、`hasChildren`,以及匹配的 `hint` / `hintPath`。 + - `config.schema` 返回 Control UI 和 CLI 工具使用的实时配置 schema 负载:schema、`uiHints`、版本和生成元数据,包括在运行时可以加载时的插件 + 渠道 schema 元数据。该 schema 包含字段 `title` / `description` 元数据,来源于 UI 使用的相同标签和帮助文本;在存在匹配字段文档时,也包括嵌套对象、通配符、数组项以及 `anyOf` / `oneOf` / `allOf` 组合分支。 + - `config.schema.lookup` 为单个配置路径返回路径范围查找负载:规范化路径、浅层 schema 节点、匹配的提示 + `hintPath`,以及供 UI/CLI 逐层钻取的直接子项摘要。查找 schema 节点保留面向用户的文档和常见验证字段(`title`、`description`、`type`、`enum`、`const`、`format`、`pattern`、数值/字符串/数组/对象边界,以及 `additionalProperties`、`deprecated`、`readOnly`、`writeOnly` 等标记)。子项摘要公开 `key`、规范化后的 `path`、`type`、`required`、`hasChildren`,以及匹配的 `hint` / `hintPath`。 - `update.run` 运行 Gateway 网关更新流程,并且仅在更新本身成功时安排重启。 - `wizard.start`、`wizard.next`、`wizard.status` 和 `wizard.cancel` 通过 WS RPC 暴露新手引导向导。 @@ -305,56 +307,56 @@ Gateway 网关将这些视为**声明**,并在服务器端强制执行 allowli - `agents.list` 返回已配置的智能体条目。 - `agents.create`、`agents.update` 和 `agents.delete` 管理智能体记录和工作区连接。 - - `agents.files.list`、`agents.files.get` 和 `agents.files.set` 管理为某个智能体公开的 bootstrap 工作区文件。 - - `agent.identity.get` 返回某个智能体或会话的生效助手身份。 - - `agent.wait` 等待一次运行结束,并在可用时返回终态快照。 + - `agents.files.list`、`agents.files.get` 和 `agents.files.set` 管理为某个智能体公开的引导工作区文件。 + - `agent.identity.get` 返回某个智能体或会话的有效助手身份。 + - `agent.wait` 等待某次运行完成,并在可用时返回终态快照。 - `sessions.list` 返回当前会话索引。 - `sessions.subscribe` 和 `sessions.unsubscribe` 为当前 WS 客户端切换会话变更事件订阅。 - - `sessions.messages.subscribe` 和 `sessions.messages.unsubscribe` 为单个会话切换 transcript / 消息事件订阅。 + - `sessions.messages.subscribe` 和 `sessions.messages.unsubscribe` 为单个会话切换 transcript/消息事件订阅。 - `sessions.preview` 返回特定会话键的有界 transcript 预览。 - - `sessions.resolve` 解析或规范化一个会话目标。 + - `sessions.resolve` 解析或规范化会话目标。 - `sessions.create` 创建新的会话条目。 - `sessions.send` 向现有会话发送消息。 - `sessions.steer` 是活动会话的中断并引导变体。 - `sessions.abort` 中止某个会话的活动工作。 - - `sessions.patch` 更新会话元数据 / 覆盖项。 + - `sessions.patch` 更新会话元数据/覆盖项。 - `sessions.reset`、`sessions.delete` 和 `sessions.compact` 执行会话维护。 - `sessions.get` 返回完整存储的会话行。 - - 聊天执行仍使用 `chat.history`、`chat.send`、`chat.abort` 和 `chat.inject`。`chat.history` 会为 UI 客户端执行显示规范化:从可见文本中移除内联指令标签,去除纯文本工具调用 XML 负载(包括 `...`、`...`、`...`、`...` 以及被截断的工具调用块)和泄漏的 ASCII / 全角模型控制标记,省略纯静默标记的助手行,例如精确的 `NO_REPLY` / `no_reply`,并且过大的行可被替换为占位符。 + - 聊天执行仍然使用 `chat.history`、`chat.send`、`chat.abort` 和 `chat.inject`。对 UI 客户端来说,`chat.history` 已做显示规范化:可见文本中的内联指令标签会被剥离,纯文本工具调用 XML 负载(包括 `...`、`...`、`...`、`...` 以及被截断的工具调用块)和泄露的 ASCII/全角模型控制令牌会被剥离,纯静默令牌的助手行(例如精确的 `NO_REPLY` / `no_reply`)会被省略,过大的行可能会被占位符替换。 - - `device.pair.list` 返回待处理和已批准的已配对设备。 + - `device.pair.list` 返回待处理和已批准的配对设备。 - `device.pair.approve`、`device.pair.reject` 和 `device.pair.remove` 管理设备配对记录。 - - `device.token.rotate` 在已批准的角色和作用域边界内轮换已配对设备令牌。 - - `device.token.revoke` 吊销已配对设备令牌。 + - `device.token.rotate` 在已批准的角色和作用域边界内轮换某个配对设备令牌。 + - `device.token.revoke` 撤销某个配对设备令牌。 - - `node.pair.request`、`node.pair.list`、`node.pair.approve`、`node.pair.reject` 和 `node.pair.verify` 涵盖节点配对和 bootstrap 验证。 - - `node.list` 和 `node.describe` 返回已知 / 已连接的节点状态。 - - `node.rename` 更新已配对节点标签。 + - `node.pair.request`、`node.pair.list`、`node.pair.approve`、`node.pair.reject` 和 `node.pair.verify` 涵盖节点配对和引导验证。 + - `node.list` 和 `node.describe` 返回已知/已连接节点状态。 + - `node.rename` 更新某个已配对节点标签。 - `node.invoke` 将命令转发到已连接节点。 - - `node.invoke.result` 返回一次调用请求的结果。 - - `node.event` 将节点发起的事件携带回 Gateway 网关。 + - `node.invoke.result` 返回某个 invoke 请求的结果。 + - `node.event` 将节点来源事件携回 Gateway 网关。 - `node.canvas.capability.refresh` 刷新带作用域的 canvas 能力令牌。 - `node.pending.pull` 和 `node.pending.ack` 是已连接节点队列 API。 - - `node.pending.enqueue` 和 `node.pending.drain` 管理离线 / 断开节点的持久待处理工作。 + - `node.pending.enqueue` 和 `node.pending.drain` 管理离线/断开连接节点的持久待处理工作。 - - - `exec.approval.request`、`exec.approval.get`、`exec.approval.list` 和 `exec.approval.resolve` 涵盖一次性 exec 批准请求以及待处理批准的查询 / 重放。 - - `exec.approval.waitDecision` 等待一个待处理 exec 批准,并返回最终决定(或在超时时返回 `null`)。 - - `exec.approvals.get` 和 `exec.approvals.set` 管理 Gateway 网关 exec 批准策略快照。 - - `exec.approvals.node.get` 和 `exec.approvals.node.set` 通过节点 relay 命令管理节点本地 exec 批准策略。 - - `plugin.approval.request`、`plugin.approval.list`、`plugin.approval.waitDecision` 和 `plugin.approval.resolve` 涵盖插件定义的批准流程。 + + - `exec.approval.request`、`exec.approval.get`、`exec.approval.list` 和 `exec.approval.resolve` 涵盖一次性 exec 审批请求,以及待处理审批的查找/重放。 + - `exec.approval.waitDecision` 等待一个待处理 exec 审批并返回最终决定(或在超时时返回 `null`)。 + - `exec.approvals.get` 和 `exec.approvals.set` 管理 Gateway 网关 exec 审批策略快照。 + - `exec.approvals.node.get` 和 `exec.approvals.node.set` 通过节点 relay 命令管理节点本地 exec 审批策略。 + - `plugin.approval.request`、`plugin.approval.list`、`plugin.approval.waitDecision` 和 `plugin.approval.resolve` 涵盖插件定义的审批流程。 - - 自动化:`wake` 安排立即或下一个 heartbeat 注入唤醒文本;`cron.list`、`cron.status`、`cron.add`、`cron.update`、`cron.remove`、`cron.run`、`cron.runs` 管理计划任务。 + - 自动化:`wake` 安排立即或下一次心跳时注入唤醒文本;`cron.list`、`cron.status`、`cron.add`、`cron.update`、`cron.remove`、`cron.run`、`cron.runs` 管理计划工作。 - Skills 和工具:`commands.list`、`skills.*`、`tools.catalog`、`tools.effective`。 @@ -362,176 +364,173 @@ Gateway 网关将这些视为**声明**,并在服务器端强制执行 allowli ### 常见事件族 - `chat`:UI 聊天更新,例如 `chat.inject` 和其他仅 transcript 的聊天事件。 -- `session.message` 和 `session.tool`:已订阅会话的 transcript / 事件流更新。 -- `sessions.changed`:会话索引或元数据已更改。 +- `session.message` 和 `session.tool`:已订阅会话的 transcript/事件流更新。 +- `sessions.changed`:会话索引或元数据已变更。 - `presence`:系统在线状态快照更新。 -- `tick`:周期性 keepalive / 存活事件。 -- `health`:Gateway 网关健康状态快照更新。 -- `heartbeat`:heartbeat 事件流更新。 -- `cron`:cron 运行 / 作业变更事件。 +- `tick`:周期性 keepalive / 存活性事件。 +- `health`:Gateway 网关健康快照更新。 +- `heartbeat`:心跳事件流更新。 +- `cron`:cron 运行/任务变更事件。 - `shutdown`:Gateway 网关关闭通知。 - `node.pair.requested` / `node.pair.resolved`:节点配对生命周期。 -- `node.invoke.request`:节点调用请求广播。 -- `device.pair.requested` / `device.pair.resolved`:已配对设备生命周期。 -- `voicewake.changed`:唤醒词触发器配置已更改。 -- `exec.approval.requested` / `exec.approval.resolved`:exec 批准生命周期。 -- `plugin.approval.requested` / `plugin.approval.resolved`:插件批准生命周期。 +- `node.invoke.request`:节点 invoke 请求广播。 +- `device.pair.requested` / `device.pair.resolved`:配对设备生命周期。 +- `voicewake.changed`:唤醒词触发器配置已变更。 +- `exec.approval.requested` / `exec.approval.resolved`:exec 审批生命周期。 +- `plugin.approval.requested` / `plugin.approval.resolved`:插件审批生命周期。 ### 节点辅助方法 -- 节点可以调用 `skills.bins` 以获取当前 Skills 可执行文件列表,用于自动允许检查。 +- 节点可以调用 `skills.bins` 以获取当前技能可执行文件列表,用于自动允许检查。 ### operator 辅助方法 -- operator 可以调用 `commands.list`(`operator.read`)来获取某个智能体的运行时命令清单。 - - `agentId` 是可选的;省略它即可读取默认智能体工作区。 - - `scope` 控制主 `name` 指向哪个表面: - - `text` 返回不带前导 `/` 的主文本命令标记 - - `native` 和默认的 `both` 路径会在可用时返回 provider 感知的原生命令名称 +- operator 可以调用 `commands.list`(`operator.read`)以获取某个智能体的运行时命令清单。 + - `agentId` 是可选项;省略时读取默认智能体工作区。 + - `scope` 控制主 `name` 目标对应哪个表面: + - `text` 返回不带前导 `/` 的主文本命令令牌 + - `native` 和默认的 `both` 路径会在可用时返回具备 provider 感知的原生命名 - `textAliases` 携带精确的斜杠别名,例如 `/model` 和 `/m`。 - - `nativeName` 在存在时携带 provider 感知的原生命令名称。 - - `provider` 是可选的,仅影响原生命名以及原生插件命令可用性。 - - `includeArgs=false` 会从响应中省略序列化的参数元数据。 -- operator 可以调用 `tools.catalog`(`operator.read`)来获取某个智能体的运行时工具目录。响应包含分组工具和来源元数据: + - `nativeName` 在存在时携带具备 provider 感知的原生命令名。 + - `provider` 是可选项,只影响原生命名以及原生插件命令可用性。 + - `includeArgs=false` 会从响应中省略序列化参数元数据。 +- operator 可以调用 `tools.catalog`(`operator.read`)以获取某个智能体的运行时工具目录。响应包含分组工具和来源元数据: - `source`:`core` 或 `plugin` - `pluginId`:当 `source="plugin"` 时的插件所有者 - `optional`:某个插件工具是否为可选 -- operator 可以调用 `tools.effective`(`operator.read`)来获取某个会话的运行时生效工具清单。 - - `sessionKey` 是必填项。 - - Gateway 网关会从服务器端的会话中派生受信任的运行时上下文,而不是接受调用方提供的 auth 或投递上下文。 - - 响应具有会话作用域,并反映当前活动对话此刻可使用的内容,包括 core、plugin 和 channel 工具。 -- operator 可以调用 `skills.status`(`operator.read`)来获取某个智能体可见的 Skills 清单。 - - `agentId` 是可选的;省略它即可读取默认智能体工作区。 - - 响应包含资格、缺失要求、配置检查和已净化的安装选项,而不会暴露原始密钥值。 -- operator 可以调用 `skills.search` 和 `skills.detail`(`operator.read`)来获取 ClawHub 发现元数据。 -- operator 可以通过两种模式调用 `skills.install`(`operator.admin`): - - ClawHub 模式:`{ source: "clawhub", slug, version?, force? }` 将一个 skill 文件夹安装到默认智能体工作区的 `skills/` 目录中。 +- operator 可以调用 `tools.effective`(`operator.read`)以获取某个会话的运行时有效工具清单。 + - `sessionKey` 为必填。 + - Gateway 网关从服务端的会话派生受信任运行时上下文,而不是接受调用方提供的 auth 或投递上下文。 + - 响应按会话范围限定,并反映当前活动对话此刻可使用的内容,包括 core、plugin 和渠道工具。 +- operator 可以调用 `skills.status`(`operator.read`)以获取某个智能体的可见技能清单。 + - `agentId` 是可选项;省略时读取默认智能体工作区。 + - 响应包含资格、缺失要求、配置检查和已清理的安装选项,但不会暴露原始秘密值。 +- operator 可以调用 `skills.search` 和 `skills.detail`(`operator.read`)以获取 ClawHub 发现元数据。 +- operator 可以调用 `skills.install`(`operator.admin`),支持两种模式: + - ClawHub 模式:`{ source: "clawhub", slug, version?, force? }` 将某个技能文件夹安装到默认智能体工作区的 `skills/` 目录。 - Gateway 网关安装器模式:`{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` - 在 Gateway 网关主机上运行已声明的 `metadata.openclaw.install` 动作。 -- operator 可以通过两种模式调用 `skills.update`(`operator.admin`): - - ClawHub 模式更新一个已跟踪的 slug,或更新默认智能体工作区中的所有已跟踪 ClawHub 安装。 + 在 Gateway 网关主机上运行声明的 `metadata.openclaw.install` 操作。 +- operator 可以调用 `skills.update`(`operator.admin`),支持两种模式: + - ClawHub 模式更新一个已跟踪 slug,或更新默认智能体工作区中的所有已跟踪 ClawHub 安装项。 - 配置模式修补 `skills.entries.` 值,例如 `enabled`、`apiKey` 和 `env`。 -## Exec 批准 +## Exec 审批 -- 当某个 exec 请求需要批准时,Gateway 网关会广播 `exec.approval.requested`。 +- 当某个 exec 请求需要审批时,Gateway 网关会广播 `exec.approval.requested`。 - operator 客户端通过调用 `exec.approval.resolve` 来处理(需要 `operator.approvals` 作用域)。 -- 对于 `host=node`,`exec.approval.request` 必须包含 `systemRunPlan`(规范化的 `argv`/`cwd`/`rawCommand`/会话元数据)。缺少 `systemRunPlan` 的请求会被拒绝。 -- 批准后,被转发的 `node.invoke system.run` 调用会重用该规范化 `systemRunPlan` 作为权威的命令 / cwd / 会话上下文。 -- 如果调用方在 prepare 与最终获批的 `system.run` 转发之间修改了 `command`、`rawCommand`、`cwd`、`agentId` 或 `sessionKey`,Gateway 网关会拒绝该运行,而不是信任被修改的负载。 +- 对于 `host=node`,`exec.approval.request` 必须包含 `systemRunPlan`(规范的 `argv`/`cwd`/`rawCommand`/会话元数据)。缺少 `systemRunPlan` 的请求会被拒绝。 +- 审批完成后,被转发的 `node.invoke system.run` 调用会复用该规范 `systemRunPlan`,作为权威的命令/cwd/会话上下文。 +- 如果调用方在 prepare 和最终获批的 `system.run` 转发之间修改了 `command`、`rawCommand`、`cwd`、`agentId` 或 `sessionKey`,Gateway 网关会拒绝此次运行,而不是信任被修改的负载。 ## 智能体投递回退 -- `agent` 请求可以包含 `deliver=true` 以请求出站投递。 +- `agent` 请求可以包含 `deliver=true`,以请求出站投递。 - `bestEffortDeliver=false` 保持严格行为:未解析或仅内部的投递目标会返回 `INVALID_REQUEST`。 -- `bestEffortDeliver=true` 允许在无法解析外部可投递路由时回退为仅会话执行(例如内部 / webchat 会话或多渠道配置含糊不清的情况)。 +- `bestEffortDeliver=true` 允许在无法解析外部可投递路由时回退到仅会话执行(例如内部/webchat 会话或有歧义的多渠道配置)。 ## 版本控制 - `PROTOCOL_VERSION` 位于 `src/gateway/protocol/schema/protocol-schemas.ts`。 -- 客户端发送 `minProtocol` + `maxProtocol`;服务器会拒绝不匹配的情况。 -- Schemas + 模型从 TypeBox 定义生成: +- 客户端发送 `minProtocol` + `maxProtocol`;服务端会拒绝不匹配情况。 +- Schemas + 模型由 TypeBox 定义生成: - `pnpm protocol:gen` - `pnpm protocol:gen:swift` - `pnpm protocol:check` ### 客户端常量 -`src/gateway/client.ts` 中的参考客户端使用这些默认值。这些值在协议 v3 中保持稳定,并且是第三方客户端预期的基线。 +`src/gateway/client.ts` 中的参考客户端使用这些默认值。这些值在协议 v3 中保持稳定,也是第三方客户端的预期基线。 | 常量 | 默认值 | 来源 | | ----------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | | `PROTOCOL_VERSION` | `3` | `src/gateway/protocol/schema/protocol-schemas.ts` | -| 请求超时(每个 RPC) | `30_000` ms | `src/gateway/client.ts` (`requestTimeoutMs`) | -| 预认证 / connect-challenge 超时 | `10_000` ms | `src/gateway/handshake-timeouts.ts`(限制在 `250`–`10_000`) | -| 初始重连退避 | `1_000` ms | `src/gateway/client.ts` (`backoffMs`) | -| 最大重连退避 | `30_000` ms | `src/gateway/client.ts` (`scheduleReconnect`) | -| device-token 关闭后的快速重试限制 | `250` ms | `src/gateway/client.ts` | -| `terminate()` 之前的强制停止宽限期 | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` | +| 请求超时(每个 RPC) | `30_000` ms | `src/gateway/client.ts`(`requestTimeoutMs`) | +| 预认证 / 连接质询超时 | `10_000` ms | `src/gateway/handshake-timeouts.ts`(限制为 `250`–`10_000`) | +| 初始重连退避 | `1_000` ms | `src/gateway/client.ts`(`backoffMs`) | +| 最大重连退避 | `30_000` ms | `src/gateway/client.ts`(`scheduleReconnect`) | +| 设备令牌关闭后的快速重试限制 | `250` ms | `src/gateway/client.ts` | +| `terminate()` 前的强制停止宽限期 | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` | | `stopAndWait()` 默认超时 | `1_000` ms | `STOP_AND_WAIT_TIMEOUT_MS` | | 默认 tick 间隔(`hello-ok` 之前) | `30_000` ms | `src/gateway/client.ts` | -| Tick 超时关闭 | 当静默超过 `tickIntervalMs * 2` 时使用代码 `4000` | `src/gateway/client.ts` | +| tick 超时关闭 | 当静默超过 `tickIntervalMs * 2` 时使用代码 `4000` | `src/gateway/client.ts` | | `MAX_PAYLOAD_BYTES` | `25 * 1024 * 1024`(25 MB) | `src/gateway/server-constants.ts` | -服务器会在 `hello-ok` 中公布生效的 `policy.tickIntervalMs`、`policy.maxPayload` 和 `policy.maxBufferedBytes`;客户端应遵循这些值,而不是握手前的默认值。 +服务端会在 `hello-ok` 中公布有效的 `policy.tickIntervalMs`、`policy.maxPayload` 和 `policy.maxBufferedBytes`;客户端应遵循这些值,而不是握手前的默认值。 ## 认证 -- 共享密钥 Gateway 网关认证使用 `connect.params.auth.token` 或 `connect.params.auth.password`,具体取决于已配置的认证模式。 -- 带身份的模式,例如 Tailscale Serve - (`gateway.auth.allowTailscale: true`)或非 loopback 的 - `gateway.auth.mode: "trusted-proxy"`,会通过请求头而不是 `connect.params.auth.*` 来满足连接认证检查。 -- 私有入口的 `gateway.auth.mode: "none"` 会完全跳过共享密钥连接认证;不要在公开 / 不受信任的入口上暴露该模式。 -- 配对后,Gateway 网关会签发一个限定到连接角色 + 作用域的**设备令牌**。它会在 `hello-ok.auth.deviceToken` 中返回,客户端应将其持久化以供后续连接使用。 +- 共享密钥 Gateway 网关认证使用 `connect.params.auth.token` 或 `connect.params.auth.password`,取决于已配置的认证模式。 +- 带身份的模式,例如 Tailscale Serve(`gateway.auth.allowTailscale: true`)或非 loopback 的 `gateway.auth.mode: "trusted-proxy"`,会通过请求头而不是 `connect.params.auth.*` 来满足连接认证检查。 +- 私有入口 `gateway.auth.mode: "none"` 会完全跳过共享密钥连接认证;不要在公共/不受信任入口上暴露此模式。 +- 配对后,Gateway 网关会签发一个按连接角色 + 作用域限定的**设备令牌**。它会在 `hello-ok.auth.deviceToken` 中返回,客户端应将其持久化,以供将来连接使用。 - 客户端应在任何成功连接后持久化主 `hello-ok.auth.deviceToken`。 -- 使用该**已存储**设备令牌重连时,也应重用该令牌已存储的已批准作用域集合。这可以保留先前已授予的读取 / 探测 / 状态访问权限,并避免在重连时悄悄收缩为更窄的隐式仅管理员作用域。 +- 使用该**已存储**设备令牌重新连接时,也应复用该令牌已存储的已批准作用域集合。这样可以保留已授予的读取/探测/状态访问权限,并避免静默将重连收缩为更窄的隐式仅 admin 作用域。 - 客户端侧连接认证组装(`src/gateway/client.ts` 中的 `selectConnectAuth`): - - `auth.password` 是正交的,设置时总会被转发。 - - `auth.token` 按优先级填充:首先是显式共享令牌,其次是显式 `deviceToken`,然后是已存储的按设备令牌(按 `deviceId` + `role` 键控)。 - - 只有在上述都未解析出 `auth.token` 时,才会发送 `auth.bootstrapToken`。共享令牌或任何已解析的设备令牌都会抑制它。 - - 在一次性 `AUTH_TOKEN_MISMATCH` 重试中自动提升已存储设备令牌,仅对**受信任端点**启用 —— local loopback,或者带有固定 `tlsFingerprint` 的 `wss://`。未固定证书的公共 `wss://` 不符合条件。 -- 额外的 `hello-ok.auth.deviceTokens` 条目是 bootstrap 交接令牌。只有当连接在受信任传输上使用 bootstrap auth 时,才持久化它们,例如 `wss://` 或 loopback / 本地配对。 -- 如果客户端提供了**显式** `deviceToken` 或显式 `scopes`,则该调用方请求的作用域集合仍然是权威的;仅当客户端重用已存储的按设备令牌时,才会重用缓存作用域。 -- 设备令牌可通过 `device.token.rotate` 和 `device.token.revoke` 轮换 / 吊销(需要 `operator.pairing` 作用域)。 -- 令牌签发 / 轮换始终受限于该设备配对条目中记录的已批准角色集合;轮换令牌不能将设备扩展到配对批准从未授予的角色。 -- 对于已配对设备令牌会话,除非调用方还具有 `operator.admin`,否则设备管理是自限域的:非管理员调用方只能移除 / 吊销 / 轮换其**自己的**设备条目。 -- `device.token.rotate` 还会根据调用方当前会话作用域检查请求的 operator 作用域集合。非管理员调用方不能将令牌轮换为比自己当前持有更宽的 operator 作用域集合。 -- 认证失败包含 `error.details.code` 以及恢复提示: + - `auth.password` 是正交的,设置后总会被转发。 + - `auth.token` 按优先级顺序填充:首先是显式共享令牌,然后是显式 `deviceToken`,再然后是已存储的按设备令牌(按 `deviceId` + `role` 键控)。 + - 仅当以上都未解析出 `auth.token` 时才会发送 `auth.bootstrapToken`。共享令牌或任何已解析的设备令牌都会抑制它。 + - 在一次性 `AUTH_TOKEN_MISMATCH` 重试中自动提升已存储设备令牌的行为,仅对**受信任端点**开放——loopback,或带固定 `tlsFingerprint` 的 `wss://`。未固定的公共 `wss://` 不符合条件。 +- 额外的 `hello-ok.auth.deviceTokens` 条目是引导交接令牌。仅当连接在受信任传输(如 `wss://` 或 loopback/local pairing)上使用引导认证时,才应持久化它们。 +- 如果客户端提供了**显式** `deviceToken` 或显式 `scopes`,则调用方请求的该作用域集合仍然是权威值;仅当客户端复用已存储的按设备令牌时,才会复用缓存作用域。 +- 设备令牌可以通过 `device.token.rotate` 和 `device.token.revoke` 轮换/撤销(需要 `operator.pairing` 作用域)。 +- 令牌签发/轮换始终受限于该设备配对条目中记录的已批准角色集合;轮换令牌不能将设备扩展到配对批准从未授予的角色。 +- 对于配对设备令牌会话,除非调用方还具有 `operator.admin`,否则设备管理是自限定的:非 admin 调用方只能移除/撤销/轮换其**自己的**设备条目。 +- `device.token.rotate` 还会根据调用方当前会话作用域检查所请求的 operator 作用域集合。非 admin 调用方不能将令牌轮换为比其当前持有范围更广的 operator 作用域集合。 +- 认证失败会包含 `error.details.code` 和恢复提示: - `error.details.canRetryWithDeviceToken`(布尔值) - `error.details.recommendedNextStep`(`retry_with_device_token`、`update_auth_configuration`、`update_auth_credentials`、`wait_then_retry`、`review_auth_configuration`) - `AUTH_TOKEN_MISMATCH` 的客户端行为: - 受信任客户端可以尝试使用缓存的按设备令牌进行一次有界重试。 - - 如果该重试失败,客户端应停止自动重连循环,并提示操作员采取行动。 + - 如果该重试失败,客户端应停止自动重连循环,并向 operator 展示操作指引。 ## 设备身份 + 配对 -- 节点应包含稳定的设备身份(`device.id`),从密钥对指纹派生。 +- 节点应包含稳定的设备身份(`device.id`),该身份派生自密钥对指纹。 - Gateway 网关按设备 + 角色签发令牌。 -- 新的设备 ID 需要配对批准,除非启用了本地自动批准。 +- 新设备 ID 需要配对批准,除非启用了本地自动批准。 - 配对自动批准以直接本地 local loopback 连接为中心。 -- OpenClaw 也为受信任共享密钥辅助流程提供了一个狭窄的后端 / 容器本地自连接路径。 -- 同主机 tailnet 或 LAN 连接在配对上仍视为远程,仍需批准。 +- OpenClaw 还为受信任的共享密钥辅助流程提供了一条狭义的后端/容器本地自连接路径。 +- 同一主机上的 tailnet 或 LAN 连接在配对上仍被视为远程连接,并且需要批准。 - 所有 WS 客户端都必须在 `connect` 期间包含 `device` 身份(operator + node)。 - Control UI 仅可在以下模式中省略它: - - `gateway.controlUi.allowInsecureAuth=true`,用于仅 localhost 的不安全 HTTP 兼容模式。 + 仅在以下模式下,Control UI 才可以省略它: + - `gateway.controlUi.allowInsecureAuth=true`,用于仅 localhost 的不安全 HTTP 兼容性。 - 成功的 `gateway.auth.mode: "trusted-proxy"` operator Control UI 认证。 - - `gateway.controlUi.dangerouslyDisableDeviceAuth=true`(紧急破窗,严重降低安全性)。 -- 所有连接都必须签署服务器提供的 `connect.challenge` nonce。 + - `gateway.controlUi.dangerouslyDisableDeviceAuth=true`(紧急破玻璃开关,严重降低安全性)。 +- 所有连接都必须对服务端提供的 `connect.challenge` nonce 进行签名。 ### 设备认证迁移诊断 -对于仍使用挑战前签名行为的旧客户端,`connect` 现在会在 `error.details.code` 下返回 `DEVICE_AUTH_*` 详情代码,并带有稳定的 `error.details.reason`。 +对于仍使用质询前签名行为的旧客户端,`connect` 现在会在 `error.details.code` 下返回 `DEVICE_AUTH_*` 详细代码,并附带稳定的 `error.details.reason`。 常见迁移失败: | 消息 | details.code | details.reason | 含义 | | --------------------------- | -------------------------------- | ------------------------ | -------------------------------------------------- | | `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | 客户端省略了 `device.nonce`(或发送了空值)。 | -| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | 客户端使用了过期 / 错误的 nonce 进行签名。 | +| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | 客户端使用了过期/错误的 nonce 进行签名。 | | `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | 签名负载与 v2 负载不匹配。 | -| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | 已签名时间戳超出允许的时间偏差。 | +| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | 签名时间戳超出允许的时钟偏差。 | | `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` 与公钥指纹不匹配。 | -| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | 公钥格式 / 规范化失败。 | +| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | 公钥格式/规范化失败。 | 迁移目标: - 始终等待 `connect.challenge`。 -- 对包含服务器 nonce 的 v2 负载进行签名。 +- 对包含服务端 nonce 的 v2 负载进行签名。 - 在 `connect.params.device.nonce` 中发送相同的 nonce。 - 首选签名负载是 `v3`,它除了 device/client/role/scopes/token/nonce 字段外,还绑定 `platform` 和 `deviceFamily`。 -- 为了兼容性,旧版 `v2` 签名仍然可被接受,但已配对设备的元数据固定仍会在重连时控制命令策略。 +- 为了兼容性,旧版 `v2` 签名仍然可接受,但配对设备元数据固定仍会在重连时控制命令策略。 ## TLS + 固定 - WS 连接支持 TLS。 -- 客户端可选择固定 Gateway 网关证书指纹(参见 `gateway.tls` - 配置,以及 `gateway.remote.tlsFingerprint` 或 CLI `--tls-fingerprint`)。 +- 客户端可以选择固定 Gateway 网关证书指纹(参见 `gateway.tls` 配置以及 `gateway.remote.tlsFingerprint` 或 CLI `--tls-fingerprint`)。 ## 范围 -此协议公开**完整的 Gateway 网关 API**(状态、渠道、模型、聊天、智能体、会话、节点、批准等)。确切表面由 `src/gateway/protocol/schema.ts` 中的 TypeBox schema 定义。 +该协议公开**完整 Gateway 网关 API**(状态、渠道、模型、聊天、智能体、会话、节点、审批等)。确切表面由 `src/gateway/protocol/schema.ts` 中的 TypeBox schemas 定义。 ## 相关内容 -- [Bridge protocol](/zh-CN/gateway/bridge-protocol) -- [Gateway runbook](/zh-CN/gateway) +- [Bridge protocol(旧版节点,历史参考)](/zh-CN/gateway/bridge-protocol) +- [Gateway 网关运行手册](/zh-CN/gateway) diff --git a/docs/zh-CN/gateway/security/index.md b/docs/zh-CN/gateway/security/index.md index fde717b69..19ee9d7fe 100644 --- a/docs/zh-CN/gateway/security/index.md +++ b/docs/zh-CN/gateway/security/index.md @@ -1,37 +1,37 @@ --- read_when: - 添加会扩大访问范围或自动化能力的功能 -summary: 运行具有 shell 访问权限的 AI Gateway 网关的安全注意事项和威胁模型 +summary: 运行具有 shell 访问权限的 AI Gateway 网关时的安全注意事项和威胁模型 title: 安全性 x-i18n: - generated_at: "2026-04-25T22:08:03Z" + generated_at: "2026-04-25T22:27:12Z" model: gpt-5.4 provider: openai - source_hash: cee231e4cfef7919296e45657a50291021c53488e537cb691306ec5dca95e44b + source_hash: 982a3164178822475c3ac3d871eb83d77c9d7cb0980ad93c781565110755e022 source_path: gateway/security/index.md workflow: 15 --- - **个人助手信任模型。** 本指南假设每个 Gateway 网关对应一个受信任的操作员边界(单用户、个人助手模型)。OpenClaw **并不是** 适用于多个敌对用户共享同一个智能体或 Gateway 网关的恶意多租户安全边界。如果你需要混合信任或敌对用户场景,请拆分信任边界(独立的 Gateway 网关 + 凭证,最好再配合独立的操作系统用户或主机)。 + **个人助理信任模型。** 本指南假设每个 Gateway 网关对应一个受信任的操作员边界(单用户、个人助理模型)。OpenClaw **并不是** 一个适用于多个对抗性用户共享同一个智能体或 Gateway 网关的敌对多租户安全边界。如果你需要混合信任或对抗性用户场景,请拆分信任边界(单独的 Gateway 网关 + 凭证,理想情况下还应使用单独的操作系统用户或主机)。 -## 先明确范围:个人助手安全模型 +## 先明确范围:个人助理安全模型 -OpenClaw 的安全指南基于**个人助手**部署:一个受信任的操作员边界,可能包含多个智能体。 +OpenClaw 的安全指南基于**个人助理**部署模型:一个受信任的操作员边界,可能包含多个智能体。 -- 支持的安全姿态:每个 Gateway 网关对应一个用户/信任边界(最好每个边界使用一个操作系统用户/主机/VPS)。 -- 不受支持的安全边界:多个彼此不信任或具有对抗关系的用户共享同一个 Gateway 网关/智能体。 -- 如果需要敌对用户隔离,请按信任边界拆分(独立的 Gateway 网关 + 凭证,最好再配合独立的操作系统用户/主机)。 -- 如果多个不受信任的用户都可以给同一个启用了工具的智能体发消息,请将其视为共享该智能体相同的委派工具权限。 +- 支持的安全姿态:每个 Gateway 网关对应一个用户/信任边界(每个边界最好对应一个操作系统用户/主机/ VPS)。 +- 不受支持的安全边界:多个彼此不受信任或具有对抗性的用户共享同一个 Gateway 网关/智能体。 +- 如果需要对抗性用户隔离,请按信任边界拆分(单独的 Gateway 网关 + 凭证,理想情况下还应使用单独的操作系统用户/主机)。 +- 如果多个不受信任的用户都可以向同一个启用了工具的智能体发消息,应视为他们共享该智能体的同一组委托工具权限。 -本页解释的是**在该模型内**如何加固。它不声称在单个共享 Gateway 网关上提供对抗性的多租户隔离。 +本页解释的是**在该模型内部**如何加固。它并不声称单个共享 Gateway 网关能够提供敌对多租户隔离。 ## 快速检查:`openclaw security audit` -另见:[Formal Verification(安全模型)](/zh-CN/security/formal-verification) +另请参阅:[Formal Verification (Security Models)](/zh-CN/security/formal-verification) -请定期运行此命令(尤其是在更改配置或暴露网络入口之后): +请定期运行此命令(尤其是在更改配置或暴露网络接口之后): ```bash openclaw security audit @@ -40,98 +40,99 @@ openclaw security audit --fix openclaw security audit --json ``` -`security audit --fix` 故意保持在较小范围内:它会把常见的开放群组策略切换为 allowlist,恢复 `logging.redactSensitive: "tools"`,收紧状态/配置/包含文件的权限,并且在 Windows 上运行时使用 Windows ACL 重置,而不是 POSIX `chmod`。 +`security audit --fix` 的修复范围被有意保持得很窄:它会将常见的开放群组策略切换为 allowlist,恢复 `logging.redactSensitive: "tools"`,收紧 state/config/include-file 权限,并且在 Windows 上运行时使用 Windows ACL 重置而不是 POSIX `chmod`。 -它会标记常见的易错配置(Gateway 网关身份验证暴露、浏览器控制暴露、高权限 allowlist、文件系统权限、宽松的 exec 审批,以及开放渠道的工具暴露)。 +它会标记常见的易踩坑配置(Gateway 网关身份验证暴露、浏览器控制暴露、高权限 allowlist、文件系统权限、过于宽松的 exec 审批,以及开放渠道的工具暴露)。 -OpenClaw 既是一个产品,也是一项实验:你正在把前沿模型行为连接到真实的消息渠道和真实工具上。**不存在“绝对安全”的配置。** 目标是有意识地明确以下几点: +OpenClaw 既是一个产品,也是一个实验:你正在把前沿模型行为接到真实的消息渠道和真实工具上。**不存在“绝对安全”的配置。** 目标是有意识地决定: -- 谁可以与你的机器人对话 -- 机器人被允许在哪些地方执行操作 -- 机器人可以接触什么 +- 谁可以和你的机器人对话 +- 机器人被允许在哪里执行操作 +- 机器人可以接触什么内容 -从仍能正常工作的最小访问范围开始,随着信心增加再逐步放宽。 +先从仍能满足需求的最小访问权限开始,随着信心增加再逐步放宽。 -### 部署与主机信任 +### 部署和主机信任 OpenClaw 假设主机和配置边界是受信任的: -- 如果某人可以修改 Gateway 网关主机状态/配置(`~/.openclaw`,包括 `openclaw.json`),应将其视为受信任的操作员。 -- 使用一个 Gateway 网关服务多个彼此不信任/具有对抗关系的操作员,**不是推荐配置**。 -- 对于混合信任团队,请使用独立的 Gateway 网关 来拆分信任边界(或者至少使用独立的操作系统用户/主机)。 -- 推荐默认做法:每台机器/主机(或 VPS)一个用户,该用户一个 Gateway 网关,该 Gateway 网关中有一个或多个智能体。 +- 如果有人可以修改 Gateway 网关主机状态/配置(`~/.openclaw`,包括 `openclaw.json`),则应将其视为受信任的操作员。 +- 让多个彼此不受信任/具有对抗性的操作员共用一个 Gateway 网关**不是推荐配置**。 +- 对于混合信任团队,请使用单独的 Gateway 网关 来拆分信任边界(或者至少使用单独的操作系统用户/主机)。 +- 推荐默认做法:每个机器/主机(或 VPS)一个用户,该用户一个 Gateway 网关,该 Gateway 网关内有一个或多个智能体。 - 在单个 Gateway 网关实例内部,经过身份验证的操作员访问属于受信任的控制平面角色,而不是按用户划分的租户角色。 -- 会话标识符(`sessionKey`、会话 ID、标签)是路由选择器,不是授权令牌。 -- 如果多个人都可以给同一个启用了工具的智能体发消息,那么他们每个人都可以驱动同一组权限。按用户进行会话/记忆隔离有助于隐私,但不会把一个共享智能体变成按用户划分的主机授权边界。 +- 会话标识符(`sessionKey`、session ID、label)是路由选择器,不是授权令牌。 +- 如果几个人都可以向同一个启用了工具的智能体发消息,那么他们每个人都可以驱动这同一组权限。按用户划分的 session/memory 隔离有助于隐私,但不会把共享智能体变成按用户划分的主机授权模型。 ### 共享 Slack 工作区:真实风险 -如果“Slack 里的所有人都可以给机器人发消息”,核心风险是委派工具权限: +如果“Slack 中的所有人都可以给机器人发消息”,核心风险是委托工具权限: -- 任何被允许的发送者都可以在该智能体的策略范围内诱导工具调用(`exec`、浏览器、网络/文件工具); -- 来自某个发送者的提示/内容注入可能导致影响共享状态、设备或输出的操作; -- 如果一个共享智能体拥有敏感凭证/文件,任何被允许的发送者都可能通过工具使用来驱动数据外泄。 +- 任何被允许的发送者都可以在智能体策略范围内诱导工具调用(`exec`、浏览器、网络/文件工具); +- 来自某个发送者的提示词/内容注入可能导致影响共享状态、设备或输出的操作; +- 如果某个共享智能体拥有敏感凭证/文件,任何被允许的发送者都可能通过工具使用来驱动数据外泄。 -对于团队工作流,请使用具有最小工具集的独立智能体/Gateway 网关;涉及个人数据的智能体应保持私有。 +对于团队工作流,请使用带有最小工具权限的独立智能体/Gateway 网关;涉及个人数据的智能体应保持私有。 ### 公司共享智能体:可接受模式 当使用该智能体的所有人都处于同一个信任边界内(例如同一个公司团队),并且该智能体严格限定在业务范围内时,这是可接受的。 -- 在专用机器/VM/容器上运行它; +- 在专用机器/虚拟机/容器上运行它; - 为该运行时使用专用操作系统用户 + 专用浏览器/配置文件/账号; -- 不要让该运行时登录个人 Apple/Google 账号,或个人密码管理器/浏览器配置文件。 +- 不要让该运行时登录你的个人 Apple/Google 账号,也不要登录个人密码管理器/浏览器配置文件。 -如果你在同一运行时中混用个人身份和公司身份,就会打破这种隔离,并增加个人数据暴露风险。 +如果你在同一个运行时中混用个人身份和公司身份,就会破坏隔离,并增加个人数据暴露风险。 -## Gateway 网关与节点的信任概念 +## Gateway 网关与 node 节点的信任概念 -应将 Gateway 网关和节点视为同一个操作员信任域中的不同角色: +应将 Gateway 网关和 node 节点视为同一个操作员信任域中的不同角色: -- **Gateway 网关** 是控制平面和策略入口(`gateway.auth`、工具策略、路由)。 -- **节点** 是与该 Gateway 网关配对的远程执行入口(命令、设备操作、主机本地能力)。 -- 通过 Gateway 网关身份验证的调用方,在 Gateway 网关范围内被视为受信任。配对之后,节点操作被视为该节点上的受信任操作员操作。 -- `sessionKey` 是路由/上下文选择,不是按用户划分的身份验证。 -- Exec 审批(allowlist + 询问)是为操作员意图设置的护栏,不是敌对多租户隔离。 -- OpenClaw 针对受信任单操作员场景的产品默认行为,是允许在 `gateway`/`node` 上直接执行主机 `exec`,无需审批提示(`security="full"`、`ask="off"`,除非你主动收紧)。这个默认值是有意设计的用户体验,并不天然构成漏洞。 -- Exec 审批会绑定精确的请求上下文以及尽力识别的直接本地文件操作数;它不会对每一种运行时/解释器加载路径做语义建模。若需要强边界,请使用沙箱隔离和主机隔离。 +- **Gateway 网关**是控制平面和策略界面(`gateway.auth`、工具策略、路由)。 +- **Node 节点**是与该 Gateway 网关配对的远程执行界面(命令、设备操作、主机本地能力)。 +- 通过身份验证访问 Gateway 网关的调用方,在 Gateway 网关范围内是受信任的。完成配对后,node 节点上的操作属于该 node 节点上的受信任操作员操作。 +- 使用共享 gateway token/password 进行身份验证的直接 loopback 后端客户端,可以在不提供用户设备身份的情况下发起内部控制平面 RPC。这并不是远程或浏览器配对绕过:网络客户端、node 客户端、device-token 客户端以及显式设备身份仍然要经过配对和 scope 升级强制执行。 +- `sessionKey` 是路由/上下文选择键,不是按用户划分的身份验证。 +- Exec 审批(allowlist + 询问)是针对操作员意图的防护栏,而不是敌对多租户隔离机制。 +- OpenClaw 针对受信任单操作员配置的产品默认行为是:允许在 `gateway`/`node` 上执行主机 exec,且无需审批提示(`security="full"`、`ask="off"`,除非你主动收紧)。这是有意设计的 UX 默认值,本身不构成漏洞。 +- Exec 审批会绑定精确的请求上下文以及尽力识别的本地文件操作数;它不会从语义上建模每一种运行时/解释器加载路径。若需要强边界,请使用沙箱隔离和主机隔离。 -如果你需要敌对用户隔离,请按操作系统用户/主机拆分信任边界,并运行独立的 Gateway 网关。 +如果你需要敌对用户隔离,请按操作系统用户/主机拆分信任边界,并运行单独的 Gateway 网关。 ## 信任边界矩阵 -在评估风险时,可将下表作为快速模型: +在进行风险分级时,可将其作为快速模型使用: -| 边界或控制项 | 它的含义 | 常见误解 | -| --------------------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- | -| `gateway.auth`(token/password/trusted-proxy/device auth) | 对 Gateway 网关 API 的调用方进行身份验证 | “要安全,就必须对每一帧消息都做按消息签名” | -| `sessionKey` | 用于上下文/会话选择的路由键 | “会话 key 是用户身份验证边界” | -| 提示/内容护栏 | 降低模型滥用风险 | “仅凭提示注入就能证明身份验证绕过” | -| `canvas.eval` / 浏览器 evaluate | 启用后属于有意提供给操作员的能力 | “在这种信任模型里,任何 JS eval 原语都自动算漏洞” | -| 本地 TUI `!` shell | 由操作员显式触发的本地执行 | “本地 shell 便捷命令属于远程注入” | -| 节点配对和节点命令 | 对已配对设备进行操作员级别的远程执行 | “远程设备控制默认应被视为不受信任用户访问” | -| `gateway.nodes.pairing.autoApproveCidrs` | 可选启用的受信任网络节点注册策略 | “默认关闭的 allowlist 也是自动配对漏洞” | +| 边界或控制项 | 含义 | 常见误解 | +| --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------- | +| `gateway.auth`(token/password/trusted-proxy/device auth) | 对 Gateway 网关 API 的调用方进行身份验证 | “必须对每一帧消息都做逐条签名才算安全” | +| `sessionKey` | 用于上下文/session 选择的路由键 | “Session key 是用户身份验证边界” | +| 提示词/内容防护栏 | 降低模型滥用风险 | “仅凭 prompt injection 就能证明 auth 绕过” | +| `canvas.eval` / 浏览器 evaluate | 启用后属于有意开放的操作员能力 | “在这个信任模型里,任何 JS eval 原语都会自动构成漏洞” | +| 本地 TUI `!` shell | 由操作员显式触发的本地执行 | “本地 shell 便捷命令就是远程注入” | +| Node 节点配对和 node 节点命令 | 对已配对设备进行操作员级远程执行 | “远程设备控制默认应视为不受信任用户访问” | +| `gateway.nodes.pairing.autoApproveCidrs` | 可选启用的受信任网络 node 节点注册策略 | “默认关闭的 allowlist 也是自动配对漏洞” | -## 按设计不属于漏洞的情况 +## 按设计不属于漏洞的问题 -以下模式经常被报告,但除非证明存在真实的边界绕过,否则通常会按无需处理关闭: +以下模式经常被报告,但通常会被判定为无需处理,除非能证明存在真实的边界绕过: -- 仅有提示注入链条,但没有策略、身份验证或沙箱隔离绕过。 -- 基于“单个共享主机或配置上存在敌对多租户运行”的假设提出的指控。 -- 将正常的操作员读取路径访问(例如 `sessions.list` / `sessions.preview` / `chat.history`)在共享 Gateway 网关 配置中归类为 IDOR 的指控。 -- 仅限 localhost 部署的发现(例如仅 loopback Gateway 网关上的 HSTS)。 -- 针对本仓库中不存在的入站路径提出的 Discord 入站 webhook 签名问题。 -- 将节点配对元数据视为 `system.run` 的隐藏第二层“逐命令审批”的报告,而真实执行边界仍然是 Gateway 网关的全局节点命令策略加上节点自身的 exec 审批。 -- 将已配置的 `gateway.nodes.pairing.autoApproveCidrs` 本身视为漏洞的报告。该设置默认关闭,需要显式填写 CIDR/IP 条目,仅适用于首次 `role: node` 配对且未请求任何作用域的情况,并且不会自动批准 operator/browser/Control UI、WebChat、角色升级、作用域升级、元数据变更、公钥变更,或同主机 loopback trusted-proxy header 路径。 -- 把 `sessionKey` 当作身份验证令牌,并据此报告“缺少按用户授权”的问题。 +- 仅靠 prompt injection 的攻击链,且没有策略、身份验证或沙箱绕过。 +- 假设单个共享主机或配置上存在敌对多租户运行的主张。 +- 将正常的操作员读取路径访问(例如 `sessions.list` / `sessions.preview` / `chat.history`)在共享 Gateway 网关配置中归类为 IDOR 的主张。 +- 仅限 localhost 部署的发现(例如仅 loopback Gateway 网关缺少 HSTS)。 +- 针对本仓库中并不存在的入站路径所提出的 Discord 入站 webhook 签名问题。 +- 将 node 节点配对元数据误认为是 `system.run` 的隐藏式二次逐命令审批层,而实际上真正的执行边界仍然是 Gateway 网关的全局 node 节点命令策略加上 node 节点自身的 exec 审批。 +- 将已配置的 `gateway.nodes.pairing.autoApproveCidrs` 本身视为漏洞的报告。此设置默认关闭,要求显式填写 CIDR/IP 条目,仅适用于首次 `role: node` 配对且未请求 scopes 的情况,并且不会自动批准 operator/browser/Control UI、WebChat、role 升级、scope 升级、metadata 变更、公钥变更或同主机 loopback trusted-proxy header 路径。 +- 将 `sessionKey` 视为 auth token 的“缺少按用户授权”类问题。 -## 60 秒内完成的加固基线 +## 六十秒内完成的加固基线 -先使用这个基线配置,然后再为受信任的智能体有选择地重新启用工具: +先使用这个基线,然后再根据受信任智能体的需要有选择地重新启用工具: ```json5 { @@ -156,123 +157,122 @@ OpenClaw 假设主机和配置边界是受信任的: } ``` -这会让 Gateway 网关仅限本地访问、隔离私信,并默认禁用控制平面/运行时工具。 +这样会将 Gateway 网关限制为仅本地可访问,隔离私信,并默认禁用控制平面/运行时工具。 ## 共享收件箱快速规则 -如果不止一个人可以给你的机器人发私信: +如果有不止一个人可以给你的机器人发私信: -- 将 `session.dmScope` 设为 `"per-channel-peer"`(多账号渠道则使用 `"per-account-channel-peer"`)。 +- 设置 `session.dmScope: "per-channel-peer"`(对于多账号渠道,则使用 `"per-account-channel-peer"`)。 - 保持 `dmPolicy: "pairing"` 或使用严格的 allowlist。 -- 绝不要把共享私信和广泛工具访问组合在一起。 -- 这能加固协作式/共享式收件箱,但在用户共享主机/配置写权限时,并不是为敌对共租户隔离而设计的。 +- 不要将共享私信与广泛的工具访问权限组合使用。 +- 这可以加固协作式/共享收件箱,但并不是为共享主机/配置写权限场景下的敌对共租户隔离而设计的。 ## 上下文可见性模型 -OpenClaw 区分两个概念: +OpenClaw 将两个概念区分开来: -- **触发授权**:谁可以触发智能体(`dmPolicy`、`groupPolicy`、allowlist、提及门槛)。 +- **触发授权**:谁可以触发智能体(`dmPolicy`、`groupPolicy`、allowlist、mention gate)。 - **上下文可见性**:哪些补充上下文会被注入到模型输入中(回复正文、引用文本、线程历史、转发元数据)。 -Allowlist 用于限制触发和命令授权。`contextVisibility` 设置控制如何过滤补充上下文(引用回复、线程根消息、拉取的历史记录): +Allowlists 控制触发和命令授权。`contextVisibility` 设置控制如何过滤补充上下文(引用回复、线程根消息、获取的历史记录): -- `contextVisibility: "all"`(默认)保留接收到的全部补充上下文。 -- `contextVisibility: "allowlist"` 按当前生效的 allowlist 检查,仅保留被允许发送者的补充上下文。 -- `contextVisibility: "allowlist_quote"` 的行为与 `allowlist` 相同,但仍保留一条显式引用回复。 +- `contextVisibility: "all"`(默认)会按接收到的原样保留补充上下文。 +- `contextVisibility: "allowlist"` 会将补充上下文过滤为仅包含通过当前 allowlist 检查的发送者内容。 +- `contextVisibility: "allowlist_quote"` 的行为与 `allowlist` 类似,但仍会保留一条显式引用的回复。 -可以按渠道或按房间/对话设置 `contextVisibility`。配置细节参见 [群聊](/zh-CN/channels/groups#context-visibility-and-allowlists)。 +可按渠道或按房间/会话设置 `contextVisibility`。配置细节请参阅 [Group Chats](/zh-CN/channels/groups#context-visibility-and-allowlists)。 -安全通告分级建议: +安全通告分级指导: -- 仅能证明“模型可以看到来自未列入 allowlist 的发送者的引用文本或历史文本”的问题,应视为可通过 `contextVisibility` 进行加固的发现,而不是身份验证或沙箱隔离边界绕过。 -- 若要被认定为具有安全影响,报告仍需证明存在信任边界绕过(身份验证、策略、沙箱隔离、审批,或其他已记录的边界)。 +- 如果报告仅表明“模型可以看到来自非 allowlist 发送者的引用或历史文本”,这属于可通过 `contextVisibility` 处理的加固项,本身并不构成身份验证或沙箱边界绕过。 +- 若要被认定为具有安全影响,报告仍需展示可证明的信任边界绕过(身份验证、策略、沙箱、审批,或其他文档中定义的边界)。 -## 审计检查的内容(高层概览) +## 审计会检查什么(高层概述) - **入站访问**(私信策略、群组策略、allowlist):陌生人能否触发机器人? -- **工具影响半径**(高权限工具 + 开放房间):提示注入是否可能演变为 shell/文件/网络操作? -- **Exec 审批漂移**(`security=full`、`autoAllowSkills`、未启用 `strictInlineEval` 的解释器 allowlist):主机 exec 护栏是否仍按你的预期工作? - - `security="full"` 是广泛姿态警告,不代表一定存在 bug。它是受信任个人助手场景下的默认选择;只有当你的威胁模型需要审批或 allowlist 护栏时,才应收紧它。 +- **工具影响半径**(高权限工具 + 开放房间):prompt injection 是否可能演变为 shell/文件/网络操作? +- **Exec 审批漂移**(`security=full`、`autoAllowSkills`、未启用 `strictInlineEval` 的解释器 allowlist):主机 exec 防护栏是否仍按你的预期工作? + - `security="full"` 是广泛姿态警告,不是漏洞证明。它是受信任个人助理场景下刻意选择的默认值;只有当你的威胁模型需要审批或 allowlist 防护栏时,才需要收紧。 - **网络暴露**(Gateway 网关 bind/auth、Tailscale Serve/Funnel、弱或过短的身份验证 token)。 -- **浏览器控制暴露**(远程节点、relay 端口、远程 CDP 端点)。 -- **本地磁盘卫生**(权限、符号链接、配置 include、“同步文件夹”路径)。 +- **浏览器控制暴露**(远程 node 节点、中继端口、远程 CDP 端点)。 +- **本地磁盘卫生**(权限、符号链接、config includes、“同步文件夹”路径)。 - **插件**(插件在没有显式 allowlist 的情况下加载)。 -- **策略漂移/配置错误**(已配置沙箱 Docker 设置但沙箱模式关闭;无效的 `gateway.nodes.denyCommands` 模式,因为匹配仅针对精确命令名生效,例如 `system.run`,不会检查 shell 文本;危险的 `gateway.nodes.allowCommands` 条目;全局 `tools.profile="minimal"` 被按智能体配置覆盖;在宽松工具策略下可访问的插件自有工具)。 -- **运行时预期漂移**(例如误以为隐式 exec 仍然表示 `sandbox`,但 `tools.exec.host` 现在默认是 `auto`;或者在沙箱模式关闭时显式设置 `tools.exec.host="sandbox"`)。 -- **模型卫生**(当已配置模型看起来较旧时发出警告;不是硬性阻止)。 +- **策略漂移/错误配置**(已配置沙箱 Docker 设置但沙箱模式关闭;无效的 `gateway.nodes.denyCommands` 模式,因为匹配仅针对精确命令名,例如 `system.run`,而不会检查 shell 文本;危险的 `gateway.nodes.allowCommands` 条目;全局 `tools.profile="minimal"` 被按智能体配置覆盖;在宽松工具策略下可访问插件自有工具)。 +- **运行时期望漂移**(例如误以为隐式 exec 仍表示 `sandbox`,而此时 `tools.exec.host` 默认已变为 `auto`;或者显式设置 `tools.exec.host="sandbox"`,但沙箱模式实际上是关闭的)。 +- **模型卫生**(当配置的模型看起来较旧时发出警告;不是硬性阻止)。 -如果你运行 `--deep`,OpenClaw 还会尽力尝试对在线 Gateway 网关进行探测。 +如果你运行 `--deep`,OpenClaw 还会尽力尝试进行一次实时 Gateway 网关探测。 ## 凭证存储映射 -在审计访问权限或决定需要备份什么时,可参考以下内容: +在审计访问权限或决定备份内容时可参考: - **WhatsApp**:`~/.openclaw/credentials/whatsapp//creds.json` -- **Telegram bot token**:config/env 或 `channels.telegram.tokenFile`(仅接受常规文件;拒绝符号链接) +- **Telegram bot token**:config/env 或 `channels.telegram.tokenFile`(仅允许常规文件;拒绝符号链接) - **Discord bot token**:config/env 或 SecretRef(env/file/exec provider) -- **Slack token**:config/env(`channels.slack.*`) -- **配对 allowlist**: +- **Slack tokens**:config/env(`channels.slack.*`) +- **Pairing allowlists**: - `~/.openclaw/credentials/-allowFrom.json`(默认账号) - `~/.openclaw/credentials/--allowFrom.json`(非默认账号) -- **模型身份验证配置文件**:`~/.openclaw/agents//agent/auth-profiles.json` +- **模型 auth profiles**:`~/.openclaw/agents//agent/auth-profiles.json` - **基于文件的 secrets 负载(可选)**:`~/.openclaw/secrets.json` - **旧版 OAuth 导入**:`~/.openclaw/credentials/oauth.json` -## 安全审计检查清单 +## 安全审计清单 -当审计输出发现项时,请按以下优先级处理: +当审计输出发现项时,请按以下优先顺序处理: -1. **任何“开放”状态 + 已启用工具**:先锁定私信/群组(配对/allowlist),然后收紧工具策略/沙箱隔离。 -2. **公共网络暴露**(LAN bind、Funnel、缺少 auth):立即修复。 -3. **浏览器控制远程暴露**:将其视为操作员访问权限(仅限 tailnet,谨慎配对节点,避免公开暴露)。 -4. **权限**:确保状态/配置/凭证/身份验证内容对 group/world 不可读。 +1. **任何“开放”状态 + 已启用工具**:先收紧私信/群组(pairing/allowlist),然后再收紧工具策略/沙箱隔离。 +2. **公共网络暴露**(LAN bind、Funnel、缺少身份验证):立即修复。 +3. **浏览器控制远程暴露**:将其视为操作员访问(仅限 tailnet、有意识地配对 node 节点、避免公开暴露)。 +4. **权限**:确保 state/config/credentials/auth profiles 不可被 group/world 读取。 5. **插件**:只加载你明确信任的内容。 -6. **模型选择**:对任何带工具的机器人,都优先使用现代、具备更强指令防护能力的模型。 +6. **模型选择**:对于任何带工具的机器人,优先使用现代、具备更强指令加固能力的模型。 ## 安全审计术语表 -每个审计发现都会使用结构化的 `checkId` 作为键(例如 -`gateway.bind_no_auth` 或 `tools.exec.security_full_configured`)。常见的关键严重级别类别包括: +每个审计发现项都由结构化的 `checkId` 标识(例如 +`gateway.bind_no_auth` 或 `tools.exec.security_full_configured`)。常见的高严重性类别包括: -- `fs.*` — 状态、配置、凭证、身份验证配置文件的文件系统权限。 -- `gateway.*` — bind 模式、auth、Tailscale、Control UI、trusted-proxy 配置。 -- `hooks.*`、`browser.*`、`sandbox.*`、`tools.exec.*` — 各入口面的加固项。 -- `plugins.*`、`skills.*` — 插件/技能供应链和扫描发现。 -- `security.exposure.*` — 访问策略与工具影响半径交汇处的跨领域检查。 +- `fs.*` — state、config、credentials、auth profiles 的文件系统权限。 +- `gateway.*` — bind 模式、auth、Tailscale、Control UI、trusted-proxy 设置。 +- `hooks.*`、`browser.*`、`sandbox.*`、`tools.exec.*` — 各个界面的加固检查。 +- `plugins.*`、`skills.*` — plugin/skill 供应链和扫描发现项。 +- `security.exposure.*` — 访问策略与工具影响半径交汇的跨域检查。 -完整目录(包括严重级别、修复键和自动修复支持)见 +完整目录(含严重等级、修复键名和自动修复支持)请参阅 [Security audit checks](/zh-CN/gateway/security/audit-checks)。 -## 通过 HTTP 使用 Control UI +## 通过 HTTP 访问 Control UI -Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身份。 +Control UI 需要**安全上下文**(HTTPS 或 localhost)才能生成设备身份。 `gateway.controlUi.allowInsecureAuth` 是一个本地兼容性开关: - 在 localhost 上,当页面通过非安全 HTTP 加载时,它允许 Control UI 在没有设备身份的情况下进行身份验证。 - 它不会绕过配对检查。 - 它不会放宽远程(非 localhost)设备身份要求。 -优先使用 HTTPS(Tailscale Serve),或在 `127.0.0.1` 上打开 UI。 +优先使用 HTTPS(Tailscale Serve)或在 `127.0.0.1` 上打开 UI。 -仅用于紧急破窗场景时,`gateway.controlUi.dangerouslyDisableDeviceAuth` +仅在紧急兜底场景下,`gateway.controlUi.dangerouslyDisableDeviceAuth` 会完全禁用设备身份检查。这会严重降低安全性; -除非你正在积极调试且能够快速恢复,否则请保持关闭。 +除非你正在主动调试并且能快速恢复,否则请保持关闭。 -与这些危险标志分开的是,成功的 `gateway.auth.mode: "trusted-proxy"` -可以在没有设备身份的情况下接纳**操作员** Control UI 会话。这是 -有意设计的 auth 模式行为,并不是 `allowInsecureAuth` 的捷径,而且它 -仍然不适用于 node 角色的 Control UI 会话。 +与这些危险标志无关,成功启用 `gateway.auth.mode: "trusted-proxy"` +可以允许**操作员**的 Control UI 会话在没有设备身份的情况下接入。这是 +有意设计的 auth 模式行为,而不是 `allowInsecureAuth` 的捷径,并且它仍然 +不适用于 node-role 的 Control UI 会话。 当此设置启用时,`openclaw security audit` 会发出警告。 ## 不安全或危险标志摘要 -当已知不安全/危险的调试开关被启用时, -`openclaw security audit` 会触发 `config.insecure_or_dangerous_flags`。 -在生产环境中请保持这些设置未启用。 +当已知不安全/危险的调试开关被启用时,`openclaw security audit` 会触发 `config.insecure_or_dangerous_flags`。 +在生产环境中请保持这些开关未设置。 - + - `gateway.controlUi.allowInsecureAuth=true` - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` @@ -289,8 +289,7 @@ Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身 - `gateway.controlUi.dangerouslyDisableDeviceAuth` - `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` - 渠道名称匹配(内置渠道和插件渠道;适用时也可在 - `accounts.` 下单独设置): + 渠道名称匹配(内置渠道和插件渠道;在适用情况下,`accounts.` 下也可用): - `channels.discord.dangerouslyAllowNameMatching` - `channels.slack.dangerouslyAllowNameMatching` @@ -304,9 +303,9 @@ Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身 网络暴露: - - `channels.telegram.network.dangerouslyAllowPrivateNetwork`(也可按账号设置) + - `channels.telegram.network.dangerouslyAllowPrivateNetwork`(也支持按账号设置) - 沙箱 Docker(默认值 + 按智能体设置): + 沙箱 Docker(默认值 + 按智能体): - `agents.defaults.sandbox.docker.dangerouslyAllowReservedContainerTargets` - `agents.defaults.sandbox.docker.dangerouslyAllowExternalBindSources` @@ -318,34 +317,34 @@ Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身 ## 反向代理配置 如果你在反向代理(nginx、Caddy、Traefik 等)后面运行 Gateway 网关,请配置 -`gateway.trustedProxies`,以正确处理转发的客户端 IP。 +`gateway.trustedProxies`,以便正确处理转发后的客户端 IP。 -当 Gateway 网关检测到来自**不在** `trustedProxies` 中地址的代理头时,它将**不会**把连接视为本地客户端。如果 gateway auth 被禁用,这些连接将被拒绝。这样可以防止身份验证绕过:否则,被代理的连接可能看起来像是来自 localhost,从而自动获得信任。 +当 Gateway 网关检测到来自**不在** `trustedProxies` 中地址的代理头时,它**不会**将连接视为本地客户端。如果 gateway auth 被禁用,这些连接会被拒绝。这样可以防止身份验证绕过,因为否则经过代理的连接可能看起来像来自 localhost,从而获得自动信任。 -`gateway.trustedProxies` 也用于 `gateway.auth.mode: "trusted-proxy"`,但该 auth 模式更加严格: +`gateway.trustedProxies` 也会用于 `gateway.auth.mode: "trusted-proxy"`,但该 auth 模式更严格: -- trusted-proxy auth **对来自 loopback 源的代理默认拒绝** -- 同主机 loopback 反向代理仍然可以使用 `gateway.trustedProxies` 进行本地客户端检测和转发 IP 处理 -- 对于同主机 loopback 反向代理,请使用 token/password auth,而不是 `gateway.auth.mode: "trusted-proxy"` +- trusted-proxy auth **对来自 loopback 源的代理默认失败关闭** +- 同主机 loopback 反向代理仍可使用 `gateway.trustedProxies` 进行本地客户端识别和转发 IP 处理 +- 对于同主机 loopback 反向代理,请使用 token/password auth,而不要使用 `gateway.auth.mode: "trusted-proxy"` ```yaml gateway: trustedProxies: - "10.0.0.1" # 反向代理 IP # 可选。默认 false。 - # 仅当你的代理无法提供 X-Forwarded-For 时启用。 + # 仅当你的代理无法提供 X-Forwarded-For 时才启用。 allowRealIpFallback: false auth: mode: password password: ${OPENCLAW_GATEWAY_PASSWORD} ``` -当配置了 `trustedProxies` 时,Gateway 网关使用 `X-Forwarded-For` 来确定客户端 IP。默认情况下会忽略 `X-Real-IP`,除非显式设置 `gateway.allowRealIpFallback: true`。 +当配置了 `trustedProxies` 时,Gateway 网关会使用 `X-Forwarded-For` 来确定客户端 IP。默认会忽略 `X-Real-IP`,除非显式设置 `gateway.allowRealIpFallback: true`。 -受信任代理头不会让节点设备配对自动变为受信任。 -`gateway.nodes.pairing.autoApproveCidrs` 是一个独立的、默认关闭的 -操作员策略。即使启用,来自 loopback 源的 trusted-proxy header 路径 -也不会被节点自动批准,因为本地调用方可以伪造这些 header。 +Trusted proxy headers 不会让 node 节点设备配对自动成为受信任操作。 +`gateway.nodes.pairing.autoApproveCidrs` 是单独的、默认关闭的 +操作员策略。即使启用了它,来自 loopback 源的 trusted-proxy header 路径 +也会被排除在 node 节点自动批准之外,因为本地调用方可以伪造这些 headers。 良好的反向代理行为(覆盖传入的转发头): @@ -360,54 +359,52 @@ proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ``` -## HSTS 和 origin 注意事项 +## HSTS 和 origin 说明 -- OpenClaw gateway 以本地/loopback 优先。如果你在反向代理处终止 TLS,请在那里为面向代理的 HTTPS 域设置 HSTS。 -- 如果由 gateway 自身终止 HTTPS,你可以设置 `gateway.http.securityHeaders.strictTransportSecurity`,让 OpenClaw 在响应中发出 HSTS header。 +- OpenClaw Gateway 网关优先面向本地/loopback。如果你在反向代理处终止 TLS,请在代理所面对的 HTTPS 域名上设置 HSTS。 +- 如果由 Gateway 网关自身终止 HTTPS,你可以设置 `gateway.http.securityHeaders.strictTransportSecurity`,让 OpenClaw 响应中发出 HSTS header。 - 详细部署指南见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth#tls-termination-and-hsts)。 - 对于非 loopback 的 Control UI 部署,默认要求设置 `gateway.controlUi.allowedOrigins`。 -- `gateway.controlUi.allowedOrigins: ["*"]` 是显式的允许所有浏览器来源策略,不是加固后的默认值。除非是在严格受控的本地测试中,否则应避免使用。 -- 即使启用了通用 loopback 豁免,loopback 上的浏览器来源身份验证失败仍然会受到速率限制,但锁定键会按规范化后的 `Origin` 值划分,而不是使用一个共享的 localhost 桶。 -- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` 会启用 Host-header origin fallback 模式;应将其视为操作员主动选择的危险策略。 -- 将 DNS rebinding 和代理 Host header 行为视为部署加固问题;保持 `trustedProxies` 严格,并避免将 gateway 直接暴露到公共互联网。 +- `gateway.controlUi.allowedOrigins: ["*"]` 是显式的允许所有浏览器 origin 的策略,不是加固后的默认值。除非是在严格受控的本地测试中,否则请避免使用。 +- 即使启用了一般性的 loopback 豁免,loopback 上的浏览器 origin 身份验证失败仍会受到限速,但锁定键会按规范化后的 `Origin` 值分别作用,而不是共享一个 localhost 桶。 +- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` 会启用基于 Host header 的 origin 回退模式;应将其视为由操作员主动选择的危险策略。 +- 应将 DNS rebinding 和代理 Host header 行为视为部署加固问题;保持 `trustedProxies` 严格收敛,并避免将 Gateway 网关直接暴露到公共互联网。 -## 本地会话日志存储在磁盘上 +## 本地 session 日志会落盘保存 -OpenClaw 会将会话记录存储在磁盘上的 `~/.openclaw/agents//sessions/*.jsonl`。 -这是实现会话连续性和(可选)会话记忆索引所必需的,但这也意味着 -**任何具有文件系统访问权限的进程/用户都可以读取这些日志**。请将磁盘访问视为信任 -边界,并锁定 `~/.openclaw` 的权限(参见下方审计部分)。如果你需要 -在不同智能体之间实现更强隔离,请让它们运行在独立的操作系统用户或独立主机下。 +OpenClaw 会将 session 转录记录保存在磁盘上的 `~/.openclaw/agents//sessions/*.jsonl` 中。 +这是实现 session 连续性以及(可选)session memory 索引所必需的,但这也意味着 +**任何具有文件系统访问权限的进程/用户都可以读取这些日志**。应将磁盘访问视为信任 +边界,并收紧 `~/.openclaw` 的权限(见下方审计部分)。如果你需要在不同智能体之间实现 +更强的隔离,请让它们运行在不同的操作系统用户下,或使用不同主机。 -## 节点执行(`system.run`) +## Node 节点执行(system.run) -如果已配对一个 macOS 节点,Gateway 网关就可以在该节点上调用 `system.run`。这属于该 Mac 上的**远程代码执行**: +如果已配对一个 macOS node 节点,Gateway 网关可以在该 node 节点上调用 `system.run`。这就是在该 Mac 上的**远程代码执行**: -- 需要节点配对(审批 + token)。 -- Gateway 网关节点配对不是逐命令审批入口。它建立的是节点身份/信任以及 token 签发。 -- Gateway 网关通过 `gateway.nodes.allowCommands` / `denyCommands` 应用粗粒度的全局节点命令策略。 +- 需要 node 节点配对(审批 + token)。 +- Gateway 网关的 node 节点配对并不是逐命令审批界面。它建立的是 node 节点身份/信任以及 token 发放。 +- Gateway 网关通过 `gateway.nodes.allowCommands` / `denyCommands` 应用粗粒度的全局 node 节点命令策略。 - 在 Mac 上通过**设置 → Exec 审批**进行控制(security + ask + allowlist)。 -- 每个节点的 `system.run` 策略由节点自身的 exec 审批文件(`exec.approvals.node.*`)控制,它可以比 gateway 的全局命令 ID 策略更严格,也可以更宽松。 -- 以 `security="full"` 和 `ask="off"` 运行的节点是在遵循默认的受信任操作员模型。除非你的部署明确要求更严格的审批或 allowlist 姿态,否则应将其视为预期行为。 -- 审批模式会绑定精确的请求上下文,并在可能时绑定一个具体的本地脚本/文件操作数。如果 OpenClaw 无法为某个解释器/运行时命令准确识别出唯一的直接本地文件,那么基于审批的执行将被拒绝,而不会声称提供完整的语义覆盖。 -- 对于 `host=node`,基于审批的运行还会存储规范化的预备 - `systemRunPlan`;后续已批准的转发会复用该已存储计划,并且 gateway - 校验会拒绝调用方在审批请求创建后对命令/cwd/会话上下文所做的修改。 -- 如果你不希望远程执行,请将 security 设为**deny**,并移除该 Mac 的节点配对。 +- 每个 node 节点的 `system.run` 策略由该 node 节点自己的 exec 审批文件(`exec.approvals.node.*`)决定,它可以比 Gateway 网关的全局命令 ID 策略更严格,也可以更宽松。 +- 以 `security="full"` 和 `ask="off"` 运行的 node 节点,遵循的是默认的受信任操作员模型。除非你的部署明确要求更严格的审批或 allowlist 策略,否则应将其视为预期行为。 +- 审批模式会绑定精确的请求上下文,并在可能时绑定一个具体的本地脚本/文件操作数。如果 OpenClaw 无法为解释器/运行时命令准确识别出唯一的直接本地文件,那么基于审批的执行会被拒绝,而不是承诺提供完整的语义覆盖。 +- 对于 `host=node`,基于审批的运行还会存储一个规范化的预备 `systemRunPlan`;之后转发已获批准的请求时会复用该存储计划,并且 Gateway 网关验证会拒绝调用方在审批请求创建后对 command/cwd/session 上下文的修改。 +- 如果你不希望允许远程执行,请将 security 设置为 **deny**,并移除该 Mac 的 node 节点配对。 -这一区分对问题分级很重要: +这个区分对于分级判断很重要: -- 一个重新连接的已配对节点声明了不同的命令列表,如果 Gateway 网关全局策略和节点本地 exec 审批仍然在实际执行边界上生效,那么这本身并不构成漏洞。 -- 把节点配对元数据视为第二层隐藏的逐命令审批的报告,通常属于策略/用户体验理解混淆,而不是安全边界绕过。 +- 已配对 node 节点重连后声明了不同的命令列表,本身并不构成漏洞,只要 Gateway 网关全局策略和 node 节点本地 exec 审批仍然在强制执行真正的执行边界。 +- 将 node 节点配对元数据视为隐藏的第二层逐命令审批机制的报告,通常是策略/UX 理解混淆,而不是安全边界绕过。 -## 动态 Skills(watcher / 远程节点) +## 动态 Skills(watcher / 远程 nodes) -OpenClaw 可以在会话中途刷新 Skills 列表: +OpenClaw 可以在 session 中途刷新 Skills 列表: -- **Skills watcher**:对 `SKILL.md` 的修改可以在下一次智能体回合更新 Skills 快照。 -- **远程节点**:连接一个 macOS 节点后,可以让仅限 macOS 的 Skills 变为可用(基于二进制探测)。 +- **Skills watcher**:对 `SKILL.md` 的修改可以在下一次智能体轮次中更新 Skills 快照。 +- **远程 nodes**:连接 macOS node 节点后,可能使仅限 macOS 的 Skills 变为可用(基于 bin 探测)。 -应将 skill 文件夹视为**受信任代码**,并限制谁可以修改它们。 +应将 skill 文件夹视为**受信任代码**,并限制可修改它们的人。 ## 威胁模型 @@ -420,46 +417,45 @@ OpenClaw 可以在会话中途刷新 Skills 列表: 给你发消息的人可以: -- 试图诱骗你的 AI 做坏事 -- 通过社会工程学获取你的数据访问权限 +- 试图诱骗你的 AI 执行坏操作 +- 通过社会工程学方式获取你的数据访问权限 - 探测你的基础设施细节 ## 核心概念:先做访问控制,再谈智能 -这里的大多数失败并不是什么高级利用,而是“有人给机器人发了消息,而机器人照做了”。 +这里的大多数失败并不是花哨的漏洞利用——而是“有人给机器人发了消息,机器人照做了”。 -OpenClaw 的立场是: +OpenClaw 的立场: -- **先确认身份:** 决定谁可以与机器人对话(私信配对 / allowlist / 显式 “open”)。 -- **再限定范围:** 决定机器人被允许在哪些地方执行操作(群组 allowlist + 提及门槛、工具、沙箱隔离、设备权限)。 -- **最后才是模型:** 假设模型可能被操纵;设计时要让这种操纵的影响半径有限。 +- **身份优先:** 先决定谁可以和机器人对话(私信 pairing / allowlists / 显式 `open`)。 +- **范围其次:** 再决定机器人可以在哪里执行操作(群组 allowlists + mention gating、工具、沙箱隔离、设备权限)。 +- **模型最后:** 假设模型可能被操纵;设计时要让这种操纵的影响半径有限。 ## 命令授权模型 -斜杠命令和指令仅对**已授权发送者**生效。授权来源于 -渠道 allowlist/配对以及 `commands.useAccessGroups`(参见[配置](/zh-CN/gateway/configuration) -和[斜杠命令](/zh-CN/tools/slash-commands))。如果某个渠道的 allowlist 为空或包含 `"*"`, +Slash commands 和 directives 仅对**已授权发送者**生效。授权来源于 +渠道 allowlists/pairing 加上 `commands.useAccessGroups`(参见 [Configuration](/zh-CN/gateway/configuration) +和 [Slash commands](/zh-CN/tools/slash-commands))。如果某个渠道的 allowlist 为空或包含 `"*"`, 那么该渠道上的命令实际上就是开放的。 -`/exec` 是仅面向已授权操作员的会话内便捷功能。它**不会**写入配置,也**不会** -更改其他会话。 +`/exec` 是面向已授权操作员的仅 session 内便捷功能。它**不会**写入配置,也**不会** +修改其他 sessions。 ## 控制平面工具风险 -两个内置工具可以进行持久性的控制平面更改: +有两个内置工具可以进行持久性的控制平面更改: -- `gateway` 可以通过 `config.schema.lookup` / `config.get` 检查配置,并可通过 `config.apply`、`config.patch` 和 `update.run` 进行持久化更改。 -- `cron` 可以创建定时任务,使其在原始聊天/任务结束后继续运行。 +- `gateway` 可以通过 `config.schema.lookup` / `config.get` 检查配置,也可以通过 `config.apply`、`config.patch` 和 `update.run` 进行持久化修改。 +- `cron` 可以创建调度任务,使其在原始聊天/任务结束后继续运行。 -仅限所有者的 `gateway` 运行时工具仍然拒绝重写 -`tools.exec.ask` 或 `tools.exec.security`;旧版 `tools.bash.*` 别名会 +仅限 owner 的 `gateway` 运行时工具仍然拒绝重写 +`tools.exec.ask` 或 `tools.exec.security`;旧版 `tools.bash.*` 别名也会 在写入前被规范化为相同的受保护 exec 路径。 -由智能体驱动的 `gateway config.apply` 和 `gateway config.patch` 编辑 -默认是失败关闭的:只有一小部分 prompt、model 和 mention-gating -路径允许由智能体调整。因此,新的敏感配置树默认会受到保护, -除非它们被有意加入 allowlist。 +由智能体驱动的 `gateway config.apply` 和 `gateway config.patch` 编辑默认 +采用失败关闭:只有一小部分 prompt、model 和 mention gating 路径允许由智能体调整。 +因此,新的敏感配置树会默认受到保护,除非你有意将其加入 allowlist。 -对于任何处理不受信任内容的智能体/入口面,默认都应拒绝这些工具: +对于任何处理不受信任内容的智能体/界面,默认应拒绝这些工具: ```json5 { @@ -469,33 +465,33 @@ OpenClaw 的立场是: } ``` -`commands.restart=false` 只会阻止重启动作。它不会禁用 `gateway` 的配置/更新操作。 +`commands.restart=false` 只会阻止重启动作。它不会禁用 `gateway` 配置/更新操作。 ## 插件 -插件与 Gateway 网关**在同一进程内**运行。应将其视为受信任代码: +插件以**进程内**方式与 Gateway 网关一起运行。应将它们视为受信任代码: -- 只安装来自你信任来源的插件。 -- 优先使用显式的 `plugins.allow` allowlist。 +- 仅安装来自你信任来源的插件。 +- 优先使用显式 `plugins.allow` allowlists。 - 启用前审查插件配置。 -- 插件更改后重启 Gateway 网关。 +- 修改插件后重启 Gateway 网关。 - 如果你安装或更新插件(`openclaw plugins install `、`openclaw plugins update `),应将其视为运行不受信任代码: - 安装路径是当前插件安装根目录下对应插件的目录。 - - OpenClaw 会在安装/更新前运行内置危险代码扫描。`critical` 发现默认会阻止安装。 - - OpenClaw 使用 `npm pack`,然后在该目录中运行项目本地的 `npm install --omit=dev --ignore-scripts`。继承的全局 npm 安装设置会被忽略,以确保依赖始终保留在插件安装路径下。 - - 优先使用固定且精确的版本(`@scope/pkg@1.2.3`),并在启用前检查磁盘上解包后的代码。 - - `--dangerously-force-unsafe-install` 仅用于在插件安装/更新流程中处理内置扫描误报的紧急破窗场景。它不会绕过插件 `before_install` 钩子策略阻止,也不会绕过扫描失败。 - - 基于 Gateway 网关的 skill 依赖安装遵循同样的危险/可疑分类:内置 `critical` 发现会默认阻止,除非调用方显式设置 `dangerouslyForceUnsafeInstall`;而可疑发现仍然只会发出警告。`openclaw skills install` 仍然是独立的 ClawHub skill 下载/安装流程。 + - OpenClaw 会在安装/更新前运行内置危险代码扫描。`critical` 级发现默认会阻止安装。 + - OpenClaw 使用 `npm pack`,然后在该目录中运行项目本地的 `npm install --omit=dev --ignore-scripts`。继承来的全局 npm 安装设置会被忽略,以确保依赖保留在插件安装路径下。 + - 优先使用固定的精确版本(`@scope/pkg@1.2.3`),并在启用前检查磁盘上解包后的代码。 + - `--dangerously-force-unsafe-install` 仅用于在插件安装/更新流程中应对内置扫描误报的紧急兜底场景。它不会绕过插件 `before_install` hook 策略阻止,也不会绕过扫描失败。 + - 由 Gateway 网关驱动的 skill 依赖安装遵循相同的危险/可疑划分:内置 `critical` 发现默认会阻止,除非调用方显式设置 `dangerouslyForceUnsafeInstall`;而可疑发现仍然只是警告。`openclaw skills install` 仍然是单独的 ClawHub skill 下载/安装流程。 -详情见:[插件](/zh-CN/tools/plugin) +详情见:[Plugins](/zh-CN/tools/plugin) -## 私信访问模型:配对、allowlist、开放、禁用 +## 私信访问模型:pairing、allowlist、open、disabled -所有当前支持私信的渠道都支持 DM 策略(`dmPolicy` 或 `*.dm.policy`),它会在消息处理**之前**限制入站私信: +当前所有支持私信的渠道都支持 DM 策略(`dmPolicy` 或 `*.dm.policy`),它会在处理消息**之前**拦截入站私信: -- `pairing`(默认):未知发送者会收到一个简短的配对码,而机器人会忽略其消息,直到获得批准。配对码在 1 小时后过期;在新请求创建之前,重复私信不会重复发送配对码。默认情况下,每个渠道待处理请求最多为 **3 个**。 -- `allowlist`:未知发送者会被阻止(没有配对握手)。 -- `open`:允许任何人发送私信(公开)。**要求** 该渠道的 allowlist 包含 `"*"`(显式选择启用)。 +- `pairing`(默认):未知发送者会收到一个简短配对码,机器人会忽略其消息,直到获得批准。配对码 1 小时后过期;重复发送私信不会重复发送配对码,直到创建新的请求。默认情况下,待处理请求每个渠道最多 **3 个**。 +- `allowlist`:未知发送者会被阻止(没有 pairing 握手)。 +- `open`:允许任何人发送私信(公开)。**要求** 该渠道的 allowlist 包含 `"*"`(显式选择加入)。 - `disabled`:完全忽略入站私信。 通过 CLI 批准: @@ -505,11 +501,11 @@ openclaw pairing list openclaw pairing approve ``` -详情及磁盘文件位置见:[配对](/zh-CN/channels/pairing) +详情和磁盘文件位置见:[Pairing](/zh-CN/channels/pairing) -## 私信会话隔离(多用户模式) +## 私信 session 隔离(多用户模式) -默认情况下,OpenClaw 会将**所有私信路由到主会话**,以便你的助手在不同设备和渠道之间保持连续性。如果**多个人**可以给机器人发送私信(开放私信或多人 allowlist),请考虑隔离私信会话: +默认情况下,OpenClaw 会将**所有私信路由到主 session**,这样你的助手就能在设备和渠道之间保持连续性。如果**有多个人**可以给机器人发私信(开放私信或多人 allowlist),请考虑隔离私信 sessions: ```json5 { @@ -517,160 +513,160 @@ openclaw pairing approve } ``` -这样可以防止跨用户上下文泄露,同时保持群聊彼此隔离。 +这样可以防止跨用户上下文泄露,同时仍保持群聊隔离。 -这是消息上下文边界,不是主机管理员边界。如果用户彼此具有对抗关系,并且共享同一个 Gateway 网关主机/配置,请按信任边界运行独立的 Gateway 网关。 +这是消息上下文边界,不是主机管理员边界。如果用户彼此对抗,且共享同一个 Gateway 网关主机/配置,请按信任边界运行单独的 Gateway 网关。 ### 安全私信模式(推荐) -将上面的代码片段视为**安全私信模式**: +将上面的片段视为**安全私信模式**: -- 默认:`session.dmScope: "main"`(所有私信共享一个会话,以保持连续性)。 -- 本地 CLI 新手引导默认:当未设置时写入 `session.dmScope: "per-channel-peer"`(保留现有显式值)。 -- 安全私信模式:`session.dmScope: "per-channel-peer"`(每个渠道 + 发送者组合都获得隔离的私信上下文)。 -- 跨渠道联系人隔离:`session.dmScope: "per-peer"`(同类型所有渠道中的每个发送者共享一个会话)。 +- 默认:`session.dmScope: "main"`(所有私信共享一个 session,以保持连续性)。 +- 本地 CLI 新手引导默认:在未设置时写入 `session.dmScope: "per-channel-peer"`(保留现有显式值)。 +- 安全私信模式:`session.dmScope: "per-channel-peer"`(每个渠道 + 发送者组合获得独立的私信上下文)。 +- 跨渠道对等隔离:`session.dmScope: "per-peer"`(同一类型的所有渠道中,每个发送者共享一个 session)。 -如果你在同一个渠道上运行多个账号,请改用 `per-account-channel-peer`。如果同一个人通过多个渠道联系你,请使用 `session.identityLinks` 将这些私信会话合并为一个规范身份。参见[会话管理](/zh-CN/concepts/session)和[配置](/zh-CN/gateway/configuration)。 +如果你在同一渠道上运行多个账号,请改用 `per-account-channel-peer`。如果同一个人通过多个渠道联系你,可以使用 `session.identityLinks` 将这些私信 sessions 合并为一个规范身份。详见 [Session Management](/zh-CN/concepts/session) 和 [Configuration](/zh-CN/gateway/configuration)。 -## 私信和群组的 allowlist +## 私信和群组的 allowlists -OpenClaw 有两个彼此独立的“谁可以触发我?”层级: +OpenClaw 有两层独立的“谁能触发我?”机制: -- **私信 allowlist**(`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`;旧版:`channels.discord.dm.allowFrom`、`channels.slack.dm.allowFrom`):谁可以在私信中与机器人对话。 - - 当 `dmPolicy="pairing"` 时,批准结果会写入 `~/.openclaw/credentials/` 下按账号划分的配对 allowlist 存储中(默认账号为 `-allowFrom.json`,非默认账号为 `--allowFrom.json`),并与配置中的 allowlist 合并。 -- **群组 allowlist**(按渠道定义):机器人到底会接受哪些群组/频道/guild 的消息。 +- **私信 allowlist**(`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`;旧版:`channels.discord.dm.allowFrom`、`channels.slack.dm.allowFrom`):谁被允许在私信中与机器人对话。 + - 当 `dmPolicy="pairing"` 时,批准结果会写入 `~/.openclaw/credentials/` 下按账号划分的 pairing allowlist 存储中(默认账号使用 `-allowFrom.json`,非默认账号使用 `--allowFrom.json`),并与 config allowlists 合并。 +- **群组 allowlist**(按渠道区分):机器人总体上接受哪些群组/频道/guild 的消息。 - 常见模式: - - `channels.whatsapp.groups`、`channels.telegram.groups`、`channels.imessage.groups`:每个群组的默认值,如 `requireMention`;设置后它也会充当群组 allowlist(包含 `"*"` 以保持允许所有群组的行为)。 - - `groupPolicy="allowlist"` + `groupAllowFrom`:限制在某个群组会话**内部**谁可以触发机器人(WhatsApp/Telegram/Signal/iMessage/Microsoft Teams)。 - - `channels.discord.guilds` / `channels.slack.channels`:按入口面设置的 allowlist + 提及默认值。 - - 群组检查的顺序是:先检查 `groupPolicy`/群组 allowlist,再检查提及/回复激活。 - - 回复机器人消息(隐式提及)**不会**绕过诸如 `groupAllowFrom` 之类的发送者 allowlist。 - - **安全提示:** 应将 `dmPolicy="open"` 和 `groupPolicy="open"` 视为最后手段。它们应尽量少用;除非你完全信任房间中的每个成员,否则优先使用配对 + allowlist。 + - `channels.whatsapp.groups`、`channels.telegram.groups`、`channels.imessage.groups`:按群组设置默认值,如 `requireMention`;设置后也会充当群组 allowlist(包含 `"*"` 可保持允许所有的行为)。 + - `groupPolicy="allowlist"` + `groupAllowFrom`:限制在群组 session **内部**谁可以触发机器人(WhatsApp/Telegram/Signal/iMessage/Microsoft Teams)。 + - `channels.discord.guilds` / `channels.slack.channels`:按界面划分的 allowlists + mention 默认值。 + - 群组检查顺序如下:先检查 `groupPolicy`/群组 allowlists,再检查 mention/reply 激活。 + - 回复机器人消息(隐式 mention)**不会**绕过诸如 `groupAllowFrom` 之类的发送者 allowlists。 + - **安全说明:** 应将 `dmPolicy="open"` 和 `groupPolicy="open"` 视为最后手段。应尽量少用;除非你完全信任房间中的每个成员,否则优先使用 pairing + allowlists。 -详情见:[配置](/zh-CN/gateway/configuration) 和 [群组](/zh-CN/channels/groups) +详情见:[Configuration](/zh-CN/gateway/configuration) 和 [Groups](/zh-CN/channels/groups) -## 提示注入(它是什么,为什么重要) +## Prompt injection(它是什么,为什么重要) -提示注入是指攻击者精心构造一条消息,操纵模型执行不安全行为(“忽略你的指令”、“导出你的文件系统”、“访问这个链接并运行命令”等)。 +Prompt injection 是指攻击者构造一条消息,操纵模型去执行不安全的事情(例如“忽略你的指令”“导出你的文件系统”“打开这个链接并运行命令”等)。 -即使有很强的系统提示,**提示注入问题也没有被解决**。系统提示护栏只是软性指导;真正的强制约束来自工具策略、exec 审批、沙箱隔离和渠道 allowlist(而且操作员可以按设计关闭它们)。实践中真正有帮助的是: +即使有很强的 system prompt,**prompt injection 也没有被解决**。System prompt 防护栏只是软性指导;真正的硬性执行来自工具策略、exec 审批、沙箱隔离和渠道 allowlists(而且操作员按设计可以禁用这些机制)。实际中真正有帮助的是: -- 保持入站私信处于锁定状态(配对/allowlist)。 -- 在群组中优先使用提及门槛;避免在公共房间中使用“始终在线”的机器人。 +- 保持入站私信为锁定状态(pairing/allowlists)。 +- 在群组中优先使用 mention gating;避免在公共房间中部署“始终在线”的机器人。 - 默认将链接、附件和粘贴的指令视为不受信任内容。 -- 在沙箱中运行敏感工具执行;让 secrets 远离智能体可访问的文件系统。 -- 注意:沙箱隔离是选择性启用的。如果沙箱模式关闭,隐式 `host=auto` 会解析为 gateway 主机。显式 `host=sandbox` 仍会失败关闭,因为没有可用的沙箱运行时。如果你希望在配置中明确表达该行为,请设置 `host=gateway`。 -- 将高风险工具(`exec`、`browser`、`web_fetch`、`web_search`)限制给受信任智能体或显式 allowlist。 -- 如果你将解释器加入 allowlist(`python`、`node`、`ruby`、`perl`、`php`、`lua`、`osascript`),请启用 `tools.exec.strictInlineEval`,这样内联 eval 形式仍然需要显式审批。 -- Shell 审批分析还会拒绝 **未加引号的 heredoc** 中的 POSIX 参数展开形式(`$VAR`、`$?`、`$$`、`$1`、`$@`、`${…}`),这样 allowlist 中的 heredoc 内容就不能在 allowlist 审查时伪装成纯文本,从而偷偷进行 shell 展开。给 heredoc 终止符加引号(例如 `<<'EOF'`)即可选择字面量正文语义;未加引号且会发生变量展开的 heredoc 会被拒绝。 -- **模型选择很重要:** 较旧/较小/旧版的模型在面对提示注入和工具滥用时明显更脆弱。对于启用了工具的智能体,请使用当前可用的最强最新一代、经过指令防护强化的模型。 +- 在沙箱中执行敏感工具;不要把 secrets 放在智能体可访问的文件系统中。 +- 注意:沙箱隔离是可选启用的。如果沙箱模式关闭,隐式 `host=auto` 会解析为 gateway 主机。显式 `host=sandbox` 仍会失败关闭,因为没有可用的沙箱运行时。如果你希望在配置中明确表示该行为,请设置 `host=gateway`。 +- 将高风险工具(`exec`、`browser`、`web_fetch`、`web_search`)限制给受信任智能体或显式 allowlists。 +- 如果你对解释器进行 allowlist 配置(`python`、`node`、`ruby`、`perl`、`php`、`lua`、`osascript`),请启用 `tools.exec.strictInlineEval`,这样内联 eval 形式仍需要显式审批。 +- Shell 审批分析还会拒绝**未加引号 heredoc** 中的 POSIX 参数展开形式(`$VAR`、`$?`、`$$`、`$1`、`$@`、`${…}`),因此处于 allowlist 中的 heredoc 正文不能把 shell 展开伪装成普通文本绕过 allowlist 审查。给 heredoc 终止符加引号(例如 `<<'EOF'`)即可选择字面量正文语义;若未加引号的 heredoc 本会触发变量展开,则会被拒绝。 +- **模型选择很重要:** 较老/较小/旧版模型在抵御 prompt injection 和工具滥用方面明显更弱。对于启用了工具的智能体,请使用当前可用的最新一代、经过指令加固的最强模型。 应视为不受信任的危险信号: -- “读取这个文件/URL,然后严格按它说的做。” -- “忽略你的系统提示或安全规则。” -- “泄露你的隐藏指令或工具输出。” -- “贴出 `~/.openclaw` 或你的日志的完整内容。” +- “读取这个文件/URL,然后严格照它说的做。” +- “忽略你的 system prompt 或安全规则。” +- “透露你隐藏的指令或工具输出。” +- “把 `~/.openclaw` 或你的日志的完整内容贴出来。” ## 外部内容特殊 token 清洗 -OpenClaw 会在包装外部内容和元数据时,先移除常见的自托管 LLM chat-template 特殊 token 字面量,然后再将它们送入模型。覆盖的标记家族包括 Qwen/ChatML、Llama、Gemma、Mistral、Phi 和 GPT-OSS 的角色/回合 token。 +OpenClaw 会在包装后的外部内容和元数据到达模型之前,去除常见的自托管 LLM chat-template 特殊 token 字面量。覆盖的标记家族包括 Qwen/ChatML、Llama、Gemma、Mistral、Phi 和 GPT-OSS 的角色/轮次 token。 原因: -- 一些以前置自托管模型的 OpenAI-compatible 后端,有时会保留出现在用户文本中的特殊 token,而不是将其屏蔽。攻击者如果能够写入入站外部内容(抓取的页面、邮件正文、文件内容工具输出),否则就可能注入一个伪造的 `assistant` 或 `system` 角色边界,从而绕过包装内容的护栏。 -- 清洗发生在外部内容包装层,因此会统一适用于抓取/读取工具以及入站渠道内容,而不是按 provider 分别处理。 -- 出站模型响应已经有独立的清洗器,会从用户可见回复中移除泄露的 ``、`` 等类似脚手架。外部内容清洗则是它的入站对应项。 +- 一些前置自托管模型的 OpenAI 兼容后端,有时会保留出现在用户文本中的特殊 token,而不是将其屏蔽。攻击者如果能写入入站外部内容(如抓取的页面、邮件正文、文件内容工具输出),否则就可能注入一个伪造的 `assistant` 或 `system` 角色边界,从而逃逸包装内容防护栏。 +- 清洗发生在外部内容包装层,因此它会统一作用于 fetch/read 工具和入站渠道内容,而不是按 provider 单独处理。 +- 出站模型响应已经有单独的清洗器,用于从用户可见回复中去除泄漏的 ``、`` 以及类似脚手架。外部内容清洗器则是其入站对应机制。 -这并不能替代本页中的其他加固措施——`dmPolicy`、allowlist、exec 审批、沙箱隔离和 `contextVisibility` 仍然承担主要作用。它所解决的是一个特定的 tokenizer 层绕过问题,针对的是那些会在转发用户文本时保留特殊 token 不变的自托管技术栈。 +这并不能替代本页中的其他加固措施——`dmPolicy`、allowlists、exec 审批、沙箱隔离和 `contextVisibility` 仍然承担主要防护作用。它封堵的是一种特定的 tokenizer 层绕过:在会原样转发带有特殊 token 的用户文本的自托管技术栈中,攻击者可能利用这一点发起攻击。 ## 不安全外部内容绕过标志 -OpenClaw 包含显式绕过标志,可禁用外部内容安全包装: +OpenClaw 包含显式的绕过标志,可禁用外部内容安全包装: - `hooks.mappings[].allowUnsafeExternalContent` - `hooks.gmail.allowUnsafeExternalContent` - Cron 负载字段 `allowUnsafeExternalContent` -建议: +指导建议: - 在生产环境中保持这些设置未启用/为 false。 -- 仅在严格限定范围的调试场景中临时启用。 -- 如果启用,请隔离该智能体(沙箱隔离 + 最小工具集 + 专用会话命名空间)。 +- 仅在范围严格受控的调试场景中临时启用。 +- 如果启用,请隔离该智能体(沙箱隔离 + 最小工具集 + 专用 session 命名空间)。 Hooks 风险说明: -- Hook 负载属于不受信任内容,即使投递来自你控制的系统也是如此(邮件/文档/网页内容都可能携带提示注入)。 -- 较弱的模型层级会放大这种风险。对于由 hook 驱动的自动化,优先使用强力的现代模型层级,并保持严格的工具策略(`tools.profile: "messaging"` 或更严格),并尽可能启用沙箱隔离。 +- Hook 负载是不受信任内容,即使投递来自你可控的系统也是如此(邮件/文档/网页内容都可能携带 prompt injection)。 +- 较弱模型层级会放大此风险。对于 hook 驱动的自动化,优先使用强大的现代模型层级,并保持工具策略严格(`tools.profile: "messaging"` 或更严格),并在可能时启用沙箱隔离。 -### 提示注入并不需要公开私信 +### Prompt injection 不需要公开私信 -即使**只有你**可以给机器人发消息,提示注入仍然可能通过 +即使**只有你**可以给机器人发消息,prompt injection 仍然可能通过 机器人读取的任何**不受信任内容**发生(网页搜索/抓取结果、浏览器页面、 -邮件、文档、附件、粘贴的日志/代码)。换句话说:发送者并不是 +电子邮件、文档、附件、粘贴的日志/代码)。换句话说:发送者并不是 唯一的威胁面;**内容本身**也可能携带对抗性指令。 当工具启用时,典型风险是外泄上下文或触发 -工具调用。降低影响半径的方法包括: +工具调用。可通过以下方式缩小影响半径: -- 使用只读或禁用工具的**阅读智能体**来总结不受信任内容, +- 使用只读或禁用工具的**阅读型智能体**来总结不受信任内容, 然后再把摘要传给你的主智能体。 - 除非确有需要,否则对启用了工具的智能体关闭 `web_search` / `web_fetch` / `browser`。 -- 对于 OpenResponses URL 输入(`input_file` / `input_image`),设置严格的 +- 对于 OpenResponses URL 输入(`input_file` / `input_image`),请设置严格的 `gateway.http.endpoints.responses.files.urlAllowlist` 和 `gateway.http.endpoints.responses.images.urlAllowlist`,并保持 `maxUrlParts` 较低。 - 空 allowlist 会被视为未设置;如果你想完全禁用 URL 抓取,请使用 `files.allowUrl: false` / `images.allowUrl: false`。 + 空 allowlists 会被视为未设置;如果你想完全禁用 URL 抓取,请使用 `files.allowUrl: false` / `images.allowUrl: false`。 - 对于 OpenResponses 文件输入,解码后的 `input_file` 文本仍会作为 - **不受信任的外部内容**注入。不要因为文件文本是由 Gateway 网关本地解码, - 就假定它是可信的。注入块仍然会携带显式的 + **不受信任的外部内容**注入。不要因为文本是由 Gateway 网关本地解码的, + 就认为文件文本是可信的。注入块仍然会带有明确的 `<<>>` 边界标记以及 `Source: External` 元数据,尽管这一路径省略了更长的 `SECURITY NOTICE:` 横幅。 -- 当媒体理解在将文本附加到媒体提示前从附件文档中提取文本时, - 也会应用同样基于标记的包装。 -- 对任何接触不受信任输入的智能体启用沙箱隔离和严格的工具 allowlist。 -- 不要把 secrets 放进提示中;应通过 gateway 主机上的 env/config 传递它们。 +- 当媒体理解功能从附加文档中提取文本并将其附加到媒体 prompt 时, + 也会应用相同的基于标记的包装。 +- 对任何接触不受信任输入的智能体启用沙箱隔离和严格工具 allowlists。 +- 不要把 secrets 放进 prompts;应通过 gateway 主机上的 env/config 传递它们。 ### 自托管 LLM 后端 -OpenAI-compatible 的自托管后端,如 vLLM、SGLang、TGI、LM Studio, -或自定义 Hugging Face tokenizer 技术栈,在处理 -chat-template 特殊 token 时,可能与托管 provider 有所不同。如果某个后端会把 -`<|im_start|>`、`<|start_header_id|>` 或 `` 这样的字面字符串 -在用户内容中分词为结构化的 chat-template token, +诸如 vLLM、SGLang、TGI、LM Studio +或自定义 Hugging Face tokenizer 技术栈之类的 OpenAI 兼容自托管后端, +在处理 chat-template 特殊 token 时,行为可能与托管 provider 不同。如果某个后端会将 +用户内容中的字面字符串(例如 `<|im_start|>`、`<|start_header_id|>` 或 ``) +当作结构性的 chat-template token 来分词, 那么不受信任文本就可能尝试在 tokenizer 层伪造角色边界。 -OpenClaw 会在分发给模型之前,从包装过的 -外部内容中移除常见模型家族的特殊 token 字面量。请保持外部内容 -包装处于启用状态,并在可用时优先使用会拆分或转义 -用户提供内容中特殊 token 的后端设置。像 OpenAI -和 Anthropic 这样的托管 provider 已经在请求侧应用了自己的清洗措施。 +OpenClaw 会在将包装后的 +外部内容发送给模型之前,去除常见模型家族的特殊 token 字面量。请保持外部内容 +包装启用,并在可用时优先使用能够对用户提供内容中的特殊 +token 进行拆分或转义的后端设置。OpenAI +和 Anthropic 等托管 provider 已经在请求侧应用了自己的清洗机制。 ### 模型强度(安全说明) -不同模型层级的提示注入抵抗能力**并不一致**。更小/更便宜的模型通常更容易受到工具滥用和指令劫持的影响,尤其是在对抗性提示下。 +不同模型层级在 prompt injection 抵抗能力上**并不一致**。更小/更便宜的模型通常更容易受到工具滥用和指令劫持的影响,尤其是在对抗性 prompt 下。 -对于启用了工具的智能体,或会读取不受信任内容的智能体,较旧/较小模型带来的提示注入风险通常过高。不要在弱模型层级上运行这些工作负载。 +对于启用了工具的智能体,或会读取不受信任内容的智能体,较老/较小模型带来的 prompt injection 风险通常过高。不要在较弱模型层级上运行这些工作负载。 建议: -- 对任何能够运行工具或接触文件/网络的机器人,**使用最新一代、最高等级的模型**。 -- **不要为启用了工具的智能体或不受信任收件箱使用较旧/较弱/较小的层级**;提示注入风险过高。 -- 如果你必须使用较小的模型,请**缩小影响半径**(只读工具、强沙箱隔离、最小文件系统访问、严格 allowlist)。 -- 运行小模型时,**为所有会话启用沙箱隔离**,并且除非输入受到严格控制,否则**禁用 `web_search`/`web_fetch`/`browser`**。 -- 对于仅聊天的个人助手、输入可信且不启用工具的场景,较小模型通常是可以的。 +- 对于任何可以运行工具或接触文件/网络的机器人,**使用最新一代、最佳层级的模型**。 +- **不要在启用了工具的智能体或不受信任收件箱场景中使用较老/较弱/较小的模型层级**;prompt injection 风险过高。 +- 如果你必须使用较小模型,**缩小影响半径**(只读工具、强沙箱隔离、最小文件系统访问、严格 allowlists)。 +- 运行小模型时,**为所有 sessions 启用沙箱隔离**,并且**禁用 `web_search`/`web_fetch`/`browser`**,除非输入受到严格控制。 +- 对于仅聊天、输入可信且不使用工具的个人助理,较小模型通常是可以接受的。 -## 群组中的推理和详细输出 +## 群组中的推理与详细输出 `/reasoning`、`/verbose` 和 `/trace` 可能会暴露内部推理、工具 输出或插件诊断信息,而这些内容 -本来并不打算出现在公共渠道中。在群组场景下,应将它们视为**仅调试用途**, -除非你明确需要,否则保持关闭。 +原本并不打算出现在公开渠道中。在群组环境里,应将它们视为**仅供调试** +功能,除非你明确需要,否则请保持关闭。 -建议: +指导建议: -- 在公共房间中保持 `/reasoning`、`/verbose` 和 `/trace` 关闭。 +- 在公开房间中保持 `/reasoning`、`/verbose` 和 `/trace` 关闭。 - 如果要启用,只应在受信任的私信或严格受控的房间中启用。 - 请记住:verbose 和 trace 输出可能包含工具参数、URL、插件诊断信息以及模型看到的数据。 @@ -678,56 +674,56 @@ OpenClaw 会在分发给模型之前,从包装过的 ### 文件权限 -在 gateway 主机上保持配置和状态私有: +在 gateway 主机上保持 config + state 私有: - `~/.openclaw/openclaw.json`:`600`(仅用户可读写) - `~/.openclaw`:`700`(仅用户可访问) -`openclaw doctor` 可以发出警告并提供收紧这些权限的选项。 +`openclaw doctor` 可以发出警告,并提供收紧这些权限的建议。 -### 网络暴露(bind、端口、防火墙) +### 网络暴露(bind、port、防火墙) -Gateway 网关会在单个端口上复用 **WebSocket + HTTP**: +Gateway 网关在单个端口上复用 **WebSocket + HTTP**: - 默认:`18789` -- 配置/flags/env:`gateway.port`、`--port`、`OPENCLAW_GATEWAY_PORT` +- Config/flags/env:`gateway.port`、`--port`、`OPENCLAW_GATEWAY_PORT` -这个 HTTP 入口面包括 Control UI 和 canvas host: +这个 HTTP 界面包含 Control UI 和 canvas host: - Control UI(SPA 资源)(默认基础路径 `/`) - Canvas host:`/__openclaw__/canvas/` 和 `/__openclaw__/a2ui/`(任意 HTML/JS;应视为不受信任内容) -如果你在普通浏览器中加载 canvas 内容,应像对待其他不受信任网页一样对待它: +如果你在普通浏览器中加载 canvas 内容,应像对待其他不受信任网页一样处理它: -- 不要将 canvas host 暴露给不受信任的网络/用户。 -- 不要让 canvas 内容与特权 Web 入口面共享同一个 origin,除非你完全理解其中影响。 +- 不要把 canvas host 暴露给不受信任的网络/用户。 +- 不要让 canvas 内容与高权限网页界面共享同一 origin,除非你完全理解其影响。 Bind 模式控制 Gateway 网关监听的位置: - `gateway.bind: "loopback"`(默认):只有本地客户端可以连接。 -- 非 loopback bind(`"lan"`、`"tailnet"`、`"custom"`)会扩大攻击面。只有在启用 gateway auth(共享 token/password,或正确配置的非 loopback trusted proxy)并配合真实防火墙时才应使用。 +- 非 loopback 绑定(`"lan"`、`"tailnet"`、`"custom"`)会扩大攻击面。只有在启用 gateway auth(共享 token/password 或正确配置的非 loopback trusted proxy)并配合真实防火墙时才应使用它们。 经验法则: -- 优先选择 Tailscale Serve,而不是 LAN bind(Serve 会让 Gateway 网关保持在 loopback 上,由 Tailscale 处理访问)。 -- 如果必须绑定到 LAN,请用防火墙将端口限制为严格的源 IP allowlist;不要广泛做端口转发。 -- 绝不要在 `0.0.0.0` 上无认证暴露 Gateway 网关。 +- 优先使用 Tailscale Serve,而不是 LAN bind(Serve 会让 Gateway 网关保持在 loopback 上,并由 Tailscale 负责访问控制)。 +- 如果你必须绑定到 LAN,请通过防火墙将端口限制为严格的源 IP allowlist;不要大范围做端口转发。 +- 永远不要将未启用身份验证的 Gateway 网关暴露在 `0.0.0.0` 上。 -### 使用 UFW 的 Docker 端口发布 +### 配合 UFW 的 Docker 端口发布 -如果你在 VPS 上使用 Docker 运行 OpenClaw,请记住,已发布的容器端口 -(`-p HOST:CONTAINER` 或 Compose `ports:`)会通过 Docker 的转发链路路由, -而不仅仅经过主机的 `INPUT` 规则。 +如果你在 VPS 上通过 Docker 运行 OpenClaw,请记住,已发布的容器端口 +(`-p HOST:CONTAINER` 或 Compose `ports:`)会经过 Docker 的转发链路, +而不只是主机的 `INPUT` 规则。 为了让 Docker 流量与防火墙策略保持一致,请在 -`DOCKER-USER` 中强制规则(该链会在 Docker 自身的 accept 规则之前被评估)。 +`DOCKER-USER` 中强制执行规则(这个链会在 Docker 自己的 accept 规则之前被评估)。 在许多现代发行版上,`iptables`/`ip6tables` 使用的是 `iptables-nft` 前端, -但这些规则仍然会应用到 nftables 后端。 +但这些规则仍会应用到底层 nftables 后端。 最小 allowlist 示例(IPv4): ```bash -# /etc/ufw/after.rules(作为独立的 *filter section 追加) +# /etc/ufw/after.rules (作为独立的 *filter 段追加) *filter :DOCKER-USER - [0:0] -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN @@ -743,10 +739,10 @@ Bind 模式控制 Gateway 网关监听的位置: COMMIT ``` -IPv6 使用独立的表。如果 -启用了 Docker IPv6,请在 `/etc/ufw/after6.rules` 中添加匹配的策略。 +IPv6 有单独的表。如果启用了 Docker IPv6, +请在 `/etc/ufw/after6.rules` 中添加匹配策略。 -避免在文档示例中硬编码像 `eth0` 这样的接口名。不同 VPS 镜像上的接口名 +避免在文档片段中硬编码诸如 `eth0` 之类的接口名称。不同 VPS 镜像上的接口名称 各不相同(`ens3`、`enp*` 等),不匹配可能会意外 跳过你的拒绝规则。 @@ -759,18 +755,18 @@ ip6tables -S DOCKER-USER nmap -sT -p 1-65535 --open ``` -预期的外部开放端口应只包括你有意暴露的那些(对大多数 -配置来说:SSH + 你的反向代理端口)。 +预期的对外开放端口应该只有你有意暴露的那些(对于大多数 +配置:SSH + 你的反向代理端口)。 -### mDNS/Bonjour 发现 +### mDNS/Bonjour 设备发现 -Gateway 网关会通过 mDNS(`_openclaw-gw._tcp`,端口 5353)广播其存在,用于本地设备发现。在 full 模式下,这还包括可能暴露运行细节的 TXT 记录: +Gateway 网关会通过 mDNS 广播自身存在(`_openclaw-gw._tcp`,端口 5353),用于本地设备发现。在 full 模式下,这还包括可能暴露运行细节的 TXT 记录: -- `cliPath`:CLI 二进制文件的完整文件系统路径(会泄露用户名和安装位置) -- `sshPort`:广播主机上的 SSH 可用性 +- `cliPath`:CLI 二进制文件的完整文件系统路径(会暴露用户名和安装位置) +- `sshPort`:表明主机提供 SSH 服务 - `displayName`、`lanHost`:主机名信息 -**操作安全注意事项:** 广播基础设施细节会让本地网络中的任何人更容易进行侦察。即使是文件系统路径、SSH 可用性这类“看似无害”的信息,也能帮助攻击者绘制你的环境图谱。 +**运行安全注意事项:** 广播基础设施细节会让本地网络中的任何人更容易进行侦察。即使像文件系统路径和 SSH 可用性这样看似“无害”的信息,也有助于攻击者绘制你的环境图谱。 **建议:** @@ -784,7 +780,7 @@ Gateway 网关会通过 mDNS(`_openclaw-gw._tcp`,端口 5353)广播其存 } ``` -2. **完全禁用**:如果你不需要本地设备发现功能: +2. 如果你不需要本地设备发现,**可完全禁用**: ```json5 { @@ -794,7 +790,7 @@ Gateway 网关会通过 mDNS(`_openclaw-gw._tcp`,端口 5353)广播其存 } ``` -3. **完整模式**(选择启用):在 TXT 记录中包含 `cliPath` + `sshPort`: +3. **完整模式**(显式启用):在 TXT 记录中包含 `cliPath` + `sshPort`: ```json5 { @@ -804,19 +800,19 @@ Gateway 网关会通过 mDNS(`_openclaw-gw._tcp`,端口 5353)广播其存 } ``` -4. **环境变量**(替代方式):设置 `OPENCLAW_DISABLE_BONJOUR=1`,无需修改配置即可禁用 mDNS。 +4. **环境变量**(替代方案):设置 `OPENCLAW_DISABLE_BONJOUR=1`,无需修改配置即可禁用 mDNS。 -在最小模式下,Gateway 网关仍会广播足够用于设备发现的信息(`role`、`gatewayPort`、`transport`),但会省略 `cliPath` 和 `sshPort`。需要 CLI 路径信息的应用可以稍后通过已认证的 WebSocket 连接获取。 +在最小模式下,Gateway 网关仍会广播足够用于设备发现的信息(`role`、`gatewayPort`、`transport`),但会省略 `cliPath` 和 `sshPort`。需要 CLI 路径信息的应用可以改为通过经过身份验证的 WebSocket 连接来获取。 ### 锁定 Gateway 网关 WebSocket(本地身份验证) -Gateway 网关身份验证默认**必须启用**。如果没有配置有效的 gateway auth 路径, -Gateway 网关会拒绝 WebSocket 连接(失败关闭)。 +默认情况下**必须启用** gateway auth。如果没有配置有效的 gateway auth 路径, +Gateway 网关将拒绝 WebSocket 连接(失败关闭)。 -新手引导默认会生成一个 token(即使是 loopback),因此 +新手引导默认会生成一个 token(即使是在 loopback 上),因此 本地客户端也必须进行身份验证。 -设置一个 token,让**所有** WS 客户端都必须身份验证: +设置一个 token,使**所有** WS 客户端都必须进行身份验证: ```json5 { @@ -826,152 +822,152 @@ Gateway 网关会拒绝 WebSocket 连接(失败关闭)。 } ``` -Doctor 可以帮你生成:`openclaw doctor --generate-gateway-token`。 +Doctor 可以帮你生成一个:`openclaw doctor --generate-gateway-token`。 -注意:`gateway.remote.token` / `.password` 是客户端凭证来源。它们 -本身**不会**保护本地 WS 访问。 -仅当 `gateway.auth.*` -未设置时,本地调用路径才可以把 `gateway.remote.*` 作为回退。 -如果通过 SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password` -但未能解析,则解析会失败关闭(不会用 remote 回退来掩盖)。 -可选:使用 `wss://` 时,通过 `gateway.remote.tlsFingerprint` 固定远程 TLS。 -明文 `ws://` 默认仅限 loopback。对于受信任的私有网络 +注意:`gateway.remote.token` / `.password` 是客户端凭证来源。 +它们**不会**单独保护本地 WS 访问。 +只有当 `gateway.auth.*` 未设置时,本地调用路径才会将 `gateway.remote.*` 用作回退。 +如果通过 SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password`, +但未能解析,则会失败关闭(不会用远程回退来掩盖该问题)。 +可选:当使用 `wss://` 时,可通过 `gateway.remote.tlsFingerprint` 固定远程 TLS。 +默认情况下,明文 `ws://` 仅限 loopback。对于受信任的私有网络 路径,可在客户端进程上设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` -作为紧急破窗手段。这故意只支持进程环境变量,而不是 +作为紧急兜底。这有意仅支持进程环境变量,而不是 `openclaw.json` 配置键。 -移动端配对以及 Android 手动或扫描的 gateway 路由更加严格: -明文仅对 loopback 可接受,但私有 LAN、link-local、`.local` 和 +移动端配对以及 Android 手动或扫描的 Gateway 网关路由要求更严格: +明文连接可用于 loopback,但 private-LAN、链路本地、`.local` 和 无点主机名必须使用 TLS,除非你显式选择启用受信任私有网络明文路径。 本地设备配对: -- 为了让同主机客户端流程更顺畅,直连本地 loopback 的设备配对会自动批准。 -- OpenClaw 还提供了一条狭义的后端/容器本地自连接路径,用于受信任共享密钥辅助流程。 -- tailnet 和 LAN 连接,包括同主机 tailnet bind,都会被视为远程连接,配对时仍需审批。 -- loopback 请求中的转发 header 证据会使其失去 loopback - 本地属性。元数据升级自动批准的范围也非常有限。详见 - [Gateway 配对](/zh-CN/gateway/pairing) 中这两类规则。 +- 为了让同主机客户端体验顺畅,针对直接本地 loopback 连接的设备配对会自动批准。 +- OpenClaw 还为受信任的共享密钥辅助流程提供了一条狭窄的后端/容器本地自连接路径。 +- Tailnet 和 LAN 连接(包括同主机 tailnet 绑定)在配对上都会被视为远程连接,仍然需要批准。 +- loopback 请求上的转发 header 证据会取消其 loopback + 本地性资格。metadata 升级自动批准仅限于非常狭窄的范围。详情见 + [Gateway pairing](/zh-CN/gateway/pairing)。 -身份验证模式: +Auth 模式: -- `gateway.auth.mode: "token"`:共享 bearer token(大多数场景推荐)。 -- `gateway.auth.mode: "password"`:密码身份验证(建议通过环境变量设置:`OPENCLAW_GATEWAY_PASSWORD`)。 -- `gateway.auth.mode: "trusted-proxy"`:信任具备身份感知能力的反向代理来验证用户身份,并通过 header 传递身份(参见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth))。 +- `gateway.auth.mode: "token"`:共享 bearer token(推荐用于大多数配置)。 +- `gateway.auth.mode: "password"`:密码身份验证(建议通过 env 设置:`OPENCLAW_GATEWAY_PASSWORD`)。 +- `gateway.auth.mode: "trusted-proxy"`:信任具备身份感知能力的反向代理来对用户进行身份验证,并通过 headers 传递身份(见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth))。 -轮换检查清单(token/password): +轮换清单(token/password): 1. 生成/设置新的 secret(`gateway.auth.token` 或 `OPENCLAW_GATEWAY_PASSWORD`)。 -2. 重启 Gateway 网关(如果由 macOS 应用监管 Gateway 网关,也要重启该应用)。 -3. 更新所有远程客户端(调用该 Gateway 网关的机器上的 `gateway.remote.token` / `.password`)。 -4. 验证旧凭证已无法连接。 +2. 重启 Gateway 网关(或者如果由 macOS 应用监管 Gateway 网关,则重启该应用)。 +3. 更新所有远程客户端(在调用 Gateway 网关的机器上更新 `gateway.remote.token` / `.password`)。 +4. 验证旧凭证已无法再连接。 -### Tailscale Serve 身份 header +### Tailscale Serve 身份 headers -当 `gateway.auth.allowTailscale` 为 `true` 时(Serve 默认如此),OpenClaw -会接受 Tailscale Serve 身份 header(`tailscale-user-login`)用于 Control +当 `gateway.auth.allowTailscale` 为 `true`(Serve 的默认值)时,OpenClaw +接受 Tailscale Serve 身份 headers(`tailscale-user-login`),用于 Control UI/WebSocket 身份验证。OpenClaw 会通过本地 Tailscale 守护进程 -(`tailscale whois`)解析 `x-forwarded-for` 地址并将其与 header 匹配,以验证身份。此逻辑仅在请求命中 loopback +(`tailscale whois`)解析 `x-forwarded-for` 地址,并将其与该 header 匹配,从而验证身份。此逻辑仅会在请求命中 loopback 且包含由 Tailscale 注入的 `x-forwarded-for`、`x-forwarded-proto` 和 `x-forwarded-host` 时触发。 -在这条异步身份检查路径上,同一 `{scope, ip}` -的失败尝试会在限流器记录失败前按顺序串行处理。因此,来自同一个 Serve 客户端的并发错误重试 -可能会立即锁死第二次尝试,而不是像两个普通不匹配那样并发穿过。 +对于这条异步身份检查路径,同一 `{scope, ip}` +的失败尝试会在限流器记录失败之前被串行化处理。 +因此,同一个 Serve 客户端并发发起的错误重试,第二次尝试可能会被立即锁定, +而不会像两个普通不匹配请求那样相互竞争通过。 HTTP API 端点(例如 `/v1/*`、`/tools/invoke` 和 `/api/channels/*`) -**不会**使用 Tailscale 身份 header 身份验证。它们仍然遵循 gateway +**不会**使用 Tailscale 身份 header 身份验证。它们仍然遵循 Gateway 网关 已配置的 HTTP auth 模式。 重要边界说明: -- Gateway 网关 HTTP bearer auth 实际上等同于全有或全无的操作员访问权限。 -- 能够调用 `/v1/chat/completions`、`/v1/responses` 或 `/api/channels/*` 的凭证,应视为该 gateway 的全访问操作员 secret。 -- 在 OpenAI-compatible HTTP 入口面上,共享密钥 bearer auth 会恢复完整的默认操作员 scope(`operator.admin`、`operator.approvals`、`operator.pairing`、`operator.read`、`operator.talk.secrets`、`operator.write`)以及智能体回合的所有者语义;更窄的 `x-openclaw-scopes` 值不会削弱这条共享密钥路径。 -- HTTP 上的按请求 scope 语义,仅在请求来自带身份的模式时才适用,例如 trusted proxy auth 或私有入口上的 `gateway.auth.mode="none"`。 -- 在这些带身份的模式下,如果省略 `x-openclaw-scopes`,会回退到正常的默认操作员 scope 集;如果你想要更窄的 scope 集,请显式发送该 header。 -- `/tools/invoke` 也遵循相同的共享密钥规则:token/password bearer auth 在这里同样被视为完整操作员访问,而带身份的模式仍会尊重声明的 scope。 -- 不要与不受信任的调用方共享这些凭证;应按信任边界使用独立的 Gateway 网关。 +- Gateway 网关 HTTP bearer auth 实际上等同于全有或全无的操作员访问。 +- 能调用 `/v1/chat/completions`、`/v1/responses` 或 `/api/channels/*` 的凭证,应视为该 Gateway 网关的全权限操作员 secret。 +- 在 OpenAI 兼容 HTTP 界面上,共享密钥 bearer auth 会恢复完整的默认操作员 scopes(`operator.admin`、`operator.approvals`、`operator.pairing`、`operator.read`、`operator.talk.secrets`、`operator.write`)以及智能体轮次的 owner 语义;更窄的 `x-openclaw-scopes` 值不会缩减这条共享密钥路径。 +- HTTP 上的按请求 scope 语义,仅在请求来自带身份模式时适用,例如 trusted proxy auth 或私有入口上的 `gateway.auth.mode="none"`。 +- 在这些带身份模式下,如果省略 `x-openclaw-scopes`,会回退到正常的默认操作员 scope 集合;如果你希望更窄的 scope 集合,请显式发送该 header。 +- `/tools/invoke` 遵循相同的共享密钥规则:在该接口上,token/password bearer auth 也会被视为完全操作员访问,而带身份模式仍会遵守声明的 scopes。 +- 不要将这些凭证分享给不受信任的调用方;应按信任边界使用单独的 Gateway 网关。 -**信任假设:** 无 token 的 Serve auth 假设 gateway 主机本身是受信任的。 -不要把它视为防御同主机恶意进程的保护手段。如果不受信任的 -本地代码可能在 gateway 主机上运行,请禁用 `gateway.auth.allowTailscale`, +**信任假设:** 无 token 的 Serve auth 假设 Gateway 网关主机是受信任的。 +不要把它当作针对同主机恶意进程的保护机制。如果 Gateway 网关主机上 +可能运行不受信任的本地代码,请禁用 `gateway.auth.allowTailscale`, 并要求使用显式共享密钥身份验证,即 `gateway.auth.mode: "token"` 或 `"password"`。 -**安全规则:** 不要通过你自己的反向代理转发这些 header。如果 -你在 gateway 前面终止 TLS 或做代理,请禁用 -`gateway.auth.allowTailscale`,并改用共享密钥身份验证(`gateway.auth.mode: +**安全规则:** 不要从你自己的反向代理转发这些 headers。如果 +你在 Gateway 网关前终止 TLS 或进行代理,请禁用 +`gateway.auth.allowTailscale`,改用共享密钥身份验证(`gateway.auth.mode: "token"` 或 `"password"`)或 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth)。 -受信任代理: +Trusted proxies: -- 如果你在 Gateway 网关前终止 TLS,请将 `gateway.trustedProxies` 设置为你的代理 IP。 -- OpenClaw 会信任来自这些 IP 的 `x-forwarded-for`(或 `x-real-ip`),以确定客户端 IP,用于本地配对检查和 HTTP 身份验证/本地检查。 +- 如果你在 Gateway 网关前终止 TLS,请将 `gateway.trustedProxies` 设置为代理 IP。 +- OpenClaw 会信任来自这些 IP 的 `x-forwarded-for`(或 `x-real-ip`),以确定客户端 IP,用于本地配对检查以及 HTTP auth/本地检查。 - 确保你的代理会**覆盖** `x-forwarded-for`,并阻止对 Gateway 网关端口的直接访问。 -参见 [Tailscale](/zh-CN/gateway/tailscale) 和 [Web 概览](/zh-CN/web)。 +参见 [Tailscale](/zh-CN/gateway/tailscale) 和 [Web overview](/zh-CN/web)。 -### 通过节点主机进行浏览器控制(推荐) +### 通过 node host 进行浏览器控制(推荐) -如果你的 Gateway 网关是远程的,但浏览器运行在另一台机器上,请在浏览器所在机器上运行一个**节点主机**, -并让 Gateway 网关代理浏览器操作(参见[浏览器工具](/zh-CN/tools/browser))。 -应将节点配对视为管理员访问权限。 +如果你的 Gateway 网关位于远端,但浏览器运行在另一台机器上,请在浏览器所在机器上运行一个 **node host**, +并让 Gateway 网关代理浏览器操作(见 [Browser tool](/zh-CN/tools/browser))。 +应将 node 节点配对视为管理员访问。 推荐模式: -- 让 Gateway 网关和节点主机处于同一个 tailnet(Tailscale)中。 -- 有意识地进行节点配对;如果不需要浏览器代理路由,就禁用它。 +- 让 Gateway 网关和 node host 位于同一个 tailnet(Tailscale)中。 +- 有意识地配对该 node 节点;如果不需要浏览器代理路由,则禁用它。 避免: -- 通过 LAN 或公共互联网暴露 relay/control 端口。 +- 通过 LAN 或公共互联网暴露中继/控制端口。 - 对浏览器控制端点使用 Tailscale Funnel(公开暴露)。 ### 磁盘上的 secrets -应假设 `~/.openclaw/`(或 `$OPENCLAW_STATE_DIR/`)下的任何内容都可能包含 secret 或私有数据: +应假设 `~/.openclaw/`(或 `$OPENCLAW_STATE_DIR/`)下的任何内容都可能包含 secrets 或私有数据: -- `openclaw.json`:配置中可能包含 token(gateway、remote gateway)、provider 设置和 allowlist。 -- `credentials/**`:渠道凭证(例如 WhatsApp 凭证)、配对 allowlist、旧版 OAuth 导入。 -- `agents//agent/auth-profiles.json`:API key、token 配置文件、OAuth token,以及可选的 `keyRef`/`tokenRef`。 -- `secrets.json`(可选):供 `file` SecretRef provider(`secrets.providers`)使用的文件型 secret 负载。 -- `agents//agent/auth.json`:旧版兼容文件。发现静态 `api_key` 条目时会进行清理。 -- `agents//sessions/**`:会话记录(`*.jsonl`)+ 路由元数据(`sessions.json`),其中可能包含私信、工具输出和链接。 -- 内置插件包:已安装的插件(及其 `node_modules/`)。 -- `sandboxes/**`:工具沙箱工作区;可能会累积你在沙箱内读写的文件副本。 +- `openclaw.json`:配置中可能包含 tokens(gateway、remote gateway)、provider 设置和 allowlists。 +- `credentials/**`:渠道凭证(例如 WhatsApp 凭证)、pairing allowlists、旧版 OAuth 导入。 +- `agents//agent/auth-profiles.json`:API keys、token profiles、OAuth tokens,以及可选的 `keyRef`/`tokenRef`。 +- `secrets.json`(可选):由 `file` SecretRef providers(`secrets.providers`)使用的基于文件的 secret 负载。 +- `agents//agent/auth.json`:旧版兼容文件。发现静态 `api_key` 条目时会清除。 +- `agents//sessions/**`:session 转录(`*.jsonl`)+ 路由元数据(`sessions.json`),可能包含私信和工具输出。 +- 内置插件包:已安装插件(以及它们的 `node_modules/`)。 +- `sandboxes/**`:工具沙箱工作区;可能累积你在沙箱中读写文件的副本。 加固建议: - 保持严格权限(目录 `700`,文件 `600`)。 -- 在 gateway 主机上使用全盘加密。 +- 在 Gateway 网关主机上使用全盘加密。 - 如果主机是共享的,优先为 Gateway 网关使用专用操作系统用户账号。 ### 工作区 `.env` 文件 -OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不会让这些文件悄悄覆盖 gateway 运行时控制。 +OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不会允许这些文件悄悄覆盖 gateway 运行时控制。 -- 任何以 `OPENCLAW_*` 开头的键,都会被来自不受信任工作区 `.env` 文件的值阻止覆盖。 -- Matrix、Mattermost、IRC 和 Synology Chat 的渠道端点设置也会被阻止通过工作区 `.env` 覆盖,因此克隆出来的工作区无法通过本地端点配置重定向内置连接器流量。端点环境变量键(例如 `MATRIX_HOMESERVER`、`MATTERMOST_URL`、`IRC_HOST`、`SYNOLOGY_CHAT_INCOMING_URL`)必须来自 gateway 进程环境或 `env.shellEnv`,而不是工作区加载的 `.env`。 -- 该阻止机制是失败关闭的:将来版本新增的运行时控制变量,不能从已提交到仓库或由攻击者提供的 `.env` 中继承;该键会被忽略,gateway 会保留自己的值。 -- 受信任的进程/操作系统环境变量(gateway 自身的 shell、launchd/systemd 单元、应用 bundle)仍然有效——这个限制只作用于 `.env` 文件加载。 +- 任何以 `OPENCLAW_*` 开头的键都会被来自不受信任工作区 `.env` 文件的值拦截。 +- Matrix、Mattermost、IRC 和 Synology Chat 的渠道端点设置也会被阻止通过工作区 `.env` 覆盖,因此克隆的工作区无法通过本地端点配置重定向内置连接器流量。端点环境变量键(如 `MATRIX_HOMESERVER`、`MATTERMOST_URL`、`IRC_HOST`、`SYNOLOGY_CHAT_INCOMING_URL`)必须来自 gateway 进程环境或 `env.shellEnv`,不能来自工作区加载的 `.env`。 +- 该拦截是失败关闭的:将来版本中新增的运行时控制变量,不能从已提交或攻击者提供的 `.env` 中继承;该键会被忽略,而 gateway 会保留自己的值。 +- 受信任的进程/操作系统环境变量(gateway 自身的 shell、launchd/systemd 单元、应用包)仍然有效——这项限制只约束 `.env` 文件加载。 -原因:工作区 `.env` 文件经常与智能体代码放在一起、被意外提交,或由工具写入。阻止整个 `OPENCLAW_*` 前缀意味着,即使以后新增某个 `OPENCLAW_*` 标志,也绝不会退化成从工作区状态中静默继承。 +原因:工作区 `.env` 文件经常与智能体代码放在一起,容易被误提交,或者被工具写入。拦截整个 `OPENCLAW_*` 前缀意味着以后即使新增 `OPENCLAW_*` 标志,也绝不会退化为从工作区状态中静默继承。 -### 日志和记录(脱敏与保留) +### 日志和转录记录(脱敏与保留) -即使访问控制正确,日志和记录也可能泄露敏感信息: +即使访问控制正确,日志和转录记录仍然可能泄露敏感信息: - Gateway 网关日志可能包含工具摘要、错误和 URL。 -- 会话记录可能包含粘贴的 secret、文件内容、命令输出和链接。 +- Session 转录可能包含粘贴的 secrets、文件内容、命令输出和链接。 建议: - 保持工具摘要脱敏开启(`logging.redactSensitive: "tools"`;默认值)。 -- 通过 `logging.redactPatterns` 为你的环境添加自定义模式(token、主机名、内部 URL)。 +- 通过 `logging.redactPatterns` 为你的环境添加自定义模式(tokens、主机名、内部 URL)。 - 分享诊断信息时,优先使用 `openclaw status --all`(可直接粘贴,secrets 已脱敏),而不是原始日志。 -- 如果不需要长期保留,请清理旧的会话记录和日志文件。 +- 如果不需要长期保留,请清理旧的 session 转录和日志文件。 -详情见:[日志](/zh-CN/gateway/logging) +详情见:[Logging](/zh-CN/gateway/logging) -### 私信:默认使用配对 +### 私信:默认启用 pairing ```json5 { @@ -979,7 +975,7 @@ OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不 } ``` -### 群组:始终要求提及 +### 群组:始终要求 mention ```json { @@ -1001,11 +997,11 @@ OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不 } ``` -在群聊中,仅在被明确提及时才回复。 +在群聊中,仅在被明确提及时响应。 ### 分离号码(WhatsApp、Signal、Telegram) -对于基于电话号码的渠道,可以考虑让你的 AI 使用与个人号码不同的独立号码: +对于基于电话号码的渠道,建议考虑让你的 AI 使用与个人号码分开的号码: - 个人号码:你的对话保持私密 - 机器人号码:由 AI 处理,并设置适当边界 @@ -1014,18 +1010,18 @@ OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不 你可以通过以下组合构建只读配置: -- `agents.defaults.sandbox.workspaceAccess: "ro"`(或使用 `"none"` 来完全禁止工作区访问) +- `agents.defaults.sandbox.workspaceAccess: "ro"`(或使用 `"none"` 以完全不允许工作区访问) - 使用工具 allow/deny 列表来阻止 `write`、`edit`、`apply_patch`、`exec`、`process` 等。 其他加固选项: -- `tools.exec.applyPatch.workspaceOnly: true`(默认):确保 `apply_patch` 即使在未启用沙箱隔离时,也不能在工作区目录之外写入/删除文件。只有当你明确希望 `apply_patch` 操作工作区外文件时,才设置为 `false`。 -- `tools.fs.workspaceOnly: true`(可选):将 `read`/`write`/`edit`/`apply_patch` 路径以及原生提示图片自动加载路径限制在工作区目录中(如果你当前允许绝对路径,而又想加一道统一护栏,这会很有用)。 -- 保持文件系统根目录范围狭窄:避免把你的主目录这类宽泛根目录用作智能体工作区/沙箱工作区。宽泛根目录可能会让文件系统工具接触到敏感本地文件(例如 `~/.openclaw` 下的状态/配置)。 +- `tools.exec.applyPatch.workspaceOnly: true`(默认):确保即使沙箱隔离关闭,`apply_patch` 也无法在工作区目录之外写入/删除。只有在你明确希望 `apply_patch` 触及工作区外文件时,才将其设为 `false`。 +- `tools.fs.workspaceOnly: true`(可选):将 `read`/`write`/`edit`/`apply_patch` 路径以及原生 prompt 图像自动加载路径限制在工作区目录内(如果你当前允许绝对路径,并希望有一条统一防护栏,这会很有用)。 +- 保持文件系统根目录范围狭窄:避免把你的主目录这类宽泛根目录用作智能体工作区/沙箱工作区。过宽的根目录可能让文件系统工具接触到敏感本地文件(例如 `~/.openclaw` 下的 state/config)。 -### 安全基线(可直接复制粘贴) +### 安全基线(可直接复制/粘贴) -一个“安全默认”配置示例:保持 Gateway 网关私有、要求私信配对,并避免在群组中部署始终在线的机器人: +一个“安全默认”配置:保持 Gateway 网关私有、要求私信 pairing,并避免在群组中部署始终在线的机器人: ```json5 { @@ -1044,69 +1040,69 @@ OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不 } ``` -如果你还希望工具执行也“默认更安全”,可为任何非所有者智能体添加沙箱隔离 + 拒绝危险工具(示例见下方“按智能体划分的访问配置”)。 +如果你还希望工具执行也“默认更安全”,可为任何非 owner 智能体添加沙箱 + 拒绝危险工具(示例见下方“按智能体划分的访问配置”)。 -针对由聊天驱动的智能体回合,内置基线策略是:非所有者发送者不能使用 `cron` 或 `gateway` 工具。 +对于聊天驱动的智能体轮次,内置基线是:非 owner 发送者不能使用 `cron` 或 `gateway` 工具。 ## 沙箱隔离(推荐) 专门文档:[沙箱隔离](/zh-CN/gateway/sandboxing) -两种互补方式: +两种可互补的方法: -- **在 Docker 中运行完整 Gateway 网关**(容器边界):[Docker](/zh-CN/install/docker) -- **工具沙箱**(`agents.defaults.sandbox`,主机上运行 gateway + 经过沙箱隔离的工具;Docker 是默认后端):[沙箱隔离](/zh-CN/gateway/sandboxing) +- **将完整 Gateway 网关运行在 Docker 中**(容器边界):[Docker](/zh-CN/install/docker) +- **工具沙箱**(`agents.defaults.sandbox`,gateway 主机运行 + 工具在沙箱中隔离;Docker 是默认后端):[沙箱隔离](/zh-CN/gateway/sandboxing) -注意:为防止跨智能体访问,请将 `agents.defaults.sandbox.scope` 保持为 `"agent"`(默认) -或使用 `"session"` 以实现更严格的按会话隔离。`scope: "shared"` 会使用 +注意:为了防止跨智能体访问,请将 `agents.defaults.sandbox.scope` 保持为 `"agent"`(默认) +或使用 `"session"` 以实现更严格的按 session 隔离。`scope: "shared"` 会使用 单一容器/工作区。 -同时也要考虑沙箱中的智能体工作区访问: +还要考虑智能体在沙箱中的工作区访问: -- `agents.defaults.sandbox.workspaceAccess: "none"`(默认)会让智能体工作区不可访问;工具会在 `~/.openclaw/sandboxes` 下的沙箱工作区中运行 +- `agents.defaults.sandbox.workspaceAccess: "none"`(默认)会阻止访问智能体工作区;工具会在 `~/.openclaw/sandboxes` 下的沙箱工作区中运行 - `agents.defaults.sandbox.workspaceAccess: "ro"` 会将智能体工作区以只读方式挂载到 `/agent`(会禁用 `write`/`edit`/`apply_patch`) - `agents.defaults.sandbox.workspaceAccess: "rw"` 会将智能体工作区以读写方式挂载到 `/workspace` -- 额外的 `sandbox.docker.binds` 会根据规范化和规范路径后的源路径进行校验。如果父目录符号链接技巧或规范化后的 home 别名最终解析到诸如 `/etc`、`/var/run` 或操作系统主目录下凭证目录等受阻止根目录,仍会失败关闭。 +- 额外的 `sandbox.docker.binds` 会根据标准化和规范化后的源路径进行校验。如果它们解析到被阻止的根目录(例如 `/etc`、`/var/run` 或操作系统主目录下的凭证目录),父级符号链接技巧和规范主目录别名仍会失败关闭。 -重要:`tools.elevated` 是全局基线逃逸通道,会在沙箱之外运行 exec。默认的有效主机是 `gateway`,或者当 exec 目标配置为 `node` 时为 `node`。请保持 `tools.elevated.allowFrom` 严格,不要对陌生人启用。你还可以通过 `agents.list[].tools.elevated` 进一步按智能体限制 elevated。参见[高权限模式](/zh-CN/tools/elevated)。 +重要:`tools.elevated` 是全局基础逃逸口,用于在沙箱外运行 exec。默认情况下,其实际 host 为 `gateway`;如果 exec 目标被配置为 `node`,则实际 host 为 `node`。请保持 `tools.elevated.allowFrom` 范围严格,不要对陌生人启用它。你还可以通过 `agents.list[].tools.elevated` 对单个智能体进一步限制 elevated。详见 [Elevated Mode](/zh-CN/tools/elevated)。 -### 子智能体委派护栏 +### 子智能体委派防护栏 -如果你允许使用会话工具,请将委派给子智能体运行视为另一个边界决策: +如果你允许 session 工具,应将委派给子智能体的运行视为另一项边界决策: -- 除非智能体确实需要委派,否则应拒绝 `sessions_spawn`。 -- 保持 `agents.defaults.subagents.allowAgents` 以及任何按智能体覆盖的 `agents.list[].subagents.allowAgents` 仅限已知安全的目标智能体。 -- 对于任何必须保持沙箱隔离的工作流,请在调用 `sessions_spawn` 时使用 `sandbox: "require"`(默认值是 `inherit`)。 +- 除非智能体确实需要委派,否则拒绝 `sessions_spawn`。 +- 将 `agents.defaults.subagents.allowAgents` 以及任何按智能体覆盖的 `agents.list[].subagents.allowAgents` 限制为已知安全的目标智能体。 +- 对于任何必须保持沙箱隔离的工作流,请以 `sandbox: "require"` 调用 `sessions_spawn`(默认是 `inherit`)。 - `sandbox: "require"` 会在目标子运行时未启用沙箱隔离时快速失败。 ## 浏览器控制风险 -启用浏览器控制意味着模型可以驱动一个真实浏览器。 -如果该浏览器配置文件中已经存在已登录会话,模型就可以 +启用浏览器控制意味着模型拥有驱动真实浏览器的能力。 +如果该浏览器配置文件中已经登录了会话,模型就可以 访问这些账号和数据。应将浏览器配置文件视为**敏感状态**: - 优先为智能体使用专用配置文件(默认的 `openclaw` 配置文件)。 -- 避免让智能体使用你的个人日常浏览器配置文件。 -- 对于沙箱隔离的智能体,除非你信任它们,否则请保持主机浏览器控制关闭。 -- 独立的 loopback 浏览器控制 API 仅接受共享密钥身份验证 +- 避免让智能体使用你的个人日常主浏览器配置文件。 +- 对于启用了沙箱隔离的智能体,除非你信任它们,否则应保持主机浏览器控制关闭。 +- 独立的 loopback 浏览器控制 API 只接受共享密钥身份验证 (gateway token bearer auth 或 gateway password)。它不会使用 - trusted-proxy 或 Tailscale Serve 身份 header。 -- 将浏览器下载内容视为不受信任输入;优先使用隔离的下载目录。 -- 如果可能,请在智能体浏览器配置文件中禁用浏览器同步/密码管理器(可减少影响半径)。 -- 对于远程 gateway,应将“浏览器控制”等同看待为对该浏览器配置文件可访问内容的“操作员访问”。 -- 让 Gateway 网关和节点主机仅处于 tailnet 内;避免将浏览器控制端口暴露到 LAN 或公共互联网。 -- 不需要浏览器代理路由时,请关闭它(`gateway.nodes.browser.mode="off"`)。 -- Chrome MCP 的现有会话模式**并不**“更安全”;它能够以你的身份操作该主机上对应 Chrome 配置文件所能访问的一切。 + trusted-proxy 或 Tailscale Serve 身份 headers。 +- 应将浏览器下载内容视为不受信任输入;优先使用隔离的下载目录。 +- 如果可能,请在智能体配置文件中禁用浏览器同步/密码管理器(可缩小影响半径)。 +- 对于远程 Gateway 网关,应假设“浏览器控制”等同于对该配置文件可访问内容的“操作员访问”。 +- 保持 Gateway 网关和 node hosts 仅在 tailnet 中可访问;避免将浏览器控制端口暴露到 LAN 或公共互联网。 +- 当你不需要浏览器代理路由时,请禁用它(`gateway.nodes.browser.mode="off"`)。 +- Chrome MCP 现有会话模式**并不**“更安全”;它可以像你一样操作该主机上 Chrome 配置文件所能访问的一切。 ### 浏览器 SSRF 策略(默认严格) -OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会被阻止,除非你显式选择启用。 +默认情况下,OpenClaw 的浏览器导航策略是严格的:私有/内部目标会保持被阻止,除非你显式选择启用。 - 默认:`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 未设置,因此浏览器导航会继续阻止私有/内部/特殊用途目标。 -- 旧版别名:`browser.ssrfPolicy.allowPrivateNetwork` 仍然接受,以保持兼容性。 -- 选择启用模式:设置 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: true`,以允许私有/内部/特殊用途目标。 -- 在严格模式下,可使用 `hostnameAllowlist`(如 `*.example.com` 这样的模式)和 `allowedHostnames`(精确主机例外,包括像 `localhost` 这样的受阻止名称)来设置显式例外。 -- 为减少基于重定向的跳转,系统会在请求前检查导航目标,并在导航完成后的最终 `http(s)` URL 上再次尽力检查。 +- 旧版别名:为了兼容性,仍接受 `browser.ssrfPolicy.allowPrivateNetwork`。 +- 显式启用模式:设置 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: true`,以允许私有/内部/特殊用途目标。 +- 在严格模式下,可使用 `hostnameAllowlist`(如 `*.example.com` 这样的模式)和 `allowedHostnames`(精确主机例外,包括像 `localhost` 这样的被阻止名称)来添加显式例外。 +- 为降低基于重定向的跳转风险,系统会在请求前进行检查,并在导航完成后的最终 `http(s)` URL 上尽力再次检查。 严格策略示例: @@ -1124,9 +1120,9 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会被 ## 按智能体划分的访问配置(多智能体) -在多智能体路由中,每个智能体都可以拥有自己的沙箱隔离 + 工具策略: -可利用这一点为不同智能体配置**完全访问**、**只读**或**无访问**。 -完整细节和优先级规则见[多智能体沙箱隔离与工具](/zh-CN/tools/multi-agent-sandbox-tools)。 +在多智能体路由下,每个智能体都可以有自己的沙箱 + 工具策略: +利用这一点,你可以为每个智能体赋予**完全访问**、**只读**或**无访问权限**。 +完整细节和优先级规则见 [Multi-Agent Sandbox & Tools](/zh-CN/tools/multi-agent-sandbox-tools)。 常见用例: @@ -1174,7 +1170,7 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会被 } ``` -### 示例:无文件系统/shell 访问(允许 provider 消息工具) +### 示例:无文件系统/shell 访问(允许 provider 消息) ```json5 { @@ -1188,8 +1184,8 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会被 scope: "agent", workspaceAccess: "none", }, - // 会话工具可能泄露记录中的敏感数据。默认情况下,OpenClaw 将这些工具限制为 - // 当前会话 + 由其生成的子智能体会话,但如果需要,你可以进一步收紧。 + // Session 工具可能泄露转录中的敏感数据。默认情况下 OpenClaw 会将这些工具 + // 限制在当前 session + 其派生的子智能体 sessions 中,但如有需要你还可以进一步收紧。 // 参见配置参考中的 `tools.sessions.visibility`。 tools: { sessions: { visibility: "tree" }, // self | tree | agent | all @@ -1227,69 +1223,70 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会被 ## 事件响应 -如果你的 AI 做了不该做的事: +如果你的 AI 做了不好的事情: -### 控制局势 +### 遏制 1. **停止它:** 停止 macOS 应用(如果它在监管 Gateway 网关),或终止你的 `openclaw gateway` 进程。 -2. **关闭暴露面:** 将 `gateway.bind` 设为 `"loopback"`(或禁用 Tailscale Funnel/Serve),直到你弄清发生了什么。 -3. **冻结访问:** 将高风险私信/群组切换为 `dmPolicy: "disabled"` / 要求提及,并移除你之前可能设置的 `"*"` 全开放条目。 +2. **关闭暴露面:** 将 `gateway.bind` 设为 `"loopback"`(或禁用 Tailscale Funnel/Serve),直到你弄清楚发生了什么。 +3. **冻结访问:** 将高风险私信/群组切换为 `dmPolicy: "disabled"` / 要求 mention,并移除你之前可能设置过的 `"*"` 全部允许项。 -### 轮换(如果 secrets 泄露,则按已泄露处理) +### 轮换(如果 secrets 泄露,应假定已被攻破) -1. 轮换 Gateway 网关身份验证(`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`)并重启。 -2. 轮换所有可调用 Gateway 网关机器上的远程客户端 secret(`gateway.remote.token` / `.password`)。 -3. 轮换 provider/API 凭证(WhatsApp 凭证、Slack/Discord token、`auth-profiles.json` 中的模型/API key,以及启用时的加密 secrets 负载值)。 +1. 轮换 Gateway 网关 auth(`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`)并重启。 +2. 轮换任何能调用 Gateway 网关的机器上的远程客户端 secrets(`gateway.remote.token` / `.password`)。 +3. 轮换 provider/API 凭证(WhatsApp 凭证、Slack/Discord tokens、`auth-profiles.json` 中的 model/API keys,以及加密 secrets 负载中的值,如果有使用)。 ### 审计 1. 检查 Gateway 网关日志:`/tmp/openclaw/openclaw-YYYY-MM-DD.log`(或 `logging.file`)。 -2. 查看相关记录:`~/.openclaw/agents//sessions/*.jsonl`。 -3. 查看最近的配置变更(任何可能扩大访问范围的内容:`gateway.bind`、`gateway.auth`、私信/群组策略、`tools.elevated`、插件变更)。 +2. 查看相关转录:`~/.openclaw/agents//sessions/*.jsonl`。 +3. 检查最近的配置更改(任何可能扩大访问范围的更改:`gateway.bind`、`gateway.auth`、私信/群组策略、`tools.elevated`、插件变更)。 4. 重新运行 `openclaw security audit --deep`,并确认关键发现已解决。 -### 为报告收集材料 +### 为报告收集信息 - 时间戳、gateway 主机操作系统 + OpenClaw 版本 -- 会话记录 + 简短日志尾部(脱敏后) -- 攻击者发送了什么 + 智能体执行了什么 -- Gateway 网关是否暴露到 loopback 之外(LAN/Tailscale Funnel/Serve) +- session 转录 + 一小段日志尾部(脱敏后) +- 攻击者发送了什么 + 智能体做了什么 +- Gateway 网关是否暴露在 loopback 之外(LAN/Tailscale Funnel/Serve) ## 使用 detect-secrets 进行 secret 扫描 -CI 会在 `secrets` 作业中运行 `detect-secrets` pre-commit hook。 -推送到 `main` 时总是执行全文件扫描。Pull request 在有基线提交可用时会走已变更文件 -快速路径,否则回退为全文件扫描。如果失败,说明出现了尚未纳入 baseline 的新候选项。 +CI 会在 `secrets` job 中运行 `detect-secrets` pre-commit hook。 +推送到 `main` 时总会扫描所有文件。Pull request 在有基准提交可用时 +会走按变更文件快速路径,否则回退为全文件扫描。 +如果失败,说明存在尚未写入基线的新候选项。 ### 如果 CI 失败 -1. 在本地复现: +1. 本地复现: ```bash pre-commit run --all-files detect-secrets ``` -2. 了解这些工具: - - pre-commit 中的 `detect-secrets` 会使用仓库的 +2. 了解相关工具: + - pre-commit 中的 `detect-secrets` 会结合仓库的 baseline 和排除项运行 `detect-secrets-hook`。 - - `detect-secrets audit` 会打开交互式审核界面,将 baseline + - `detect-secrets audit` 会打开交互式审查界面,将 baseline 中的每一项标记为真实 secret 或误报。 -3. 对于真实 secret:轮换/删除它们,然后重新运行扫描以更新 baseline。 -4. 对于误报:运行交互式审计并将其标记为误报: +3. 对于真实 secrets:轮换/移除它们,然后重新运行扫描以更新 baseline。 +4. 对于误报:运行交互式审查并将其标记为误报: ```bash detect-secrets audit .secrets.baseline ``` -5. 如果你需要新增排除规则,请将其添加到 `.detect-secrets.cfg`,并使用匹配的 `--exclude-files` / `--exclude-lines` 标志重新生成 - baseline(该配置文件仅作参考;detect-secrets 不会自动读取它)。 +5. 如果你需要新的排除项,请将其添加到 `.detect-secrets.cfg`,然后使用匹配的 `--exclude-files` / `--exclude-lines` 标志重新生成 + baseline(该配置文件仅供参考;detect-secrets 不会自动读取它)。 -当更新后的 `.secrets.baseline` 反映了预期状态后,再提交它。 +当更新后的 `.secrets.baseline` 反映出预期状态后,请提交它。 ## 报告安全问题 -在 OpenClaw 中发现漏洞?请负责任地报告: +在 OpenClaw 中发现了漏洞?请负责任地报告: -1. 发送邮件至:[security@openclaw.ai](mailto:security@openclaw.ai) -2. 在修复前不要公开发布 -3. 我们会署名致谢你(除非你希望匿名) +1. 邮件: [security@openclaw.ai](mailto:security@openclaw.ai) +2. 在修复之前不要公开发布 +3. 我们会署名感谢你(除非你希望匿名) diff --git a/docs/zh-CN/gateway/troubleshooting.md b/docs/zh-CN/gateway/troubleshooting.md index 2332a1734..78c92756b 100644 --- a/docs/zh-CN/gateway/troubleshooting.md +++ b/docs/zh-CN/gateway/troubleshooting.md @@ -1,26 +1,26 @@ --- read_when: - - 故障排除中心将你引导到这里,以进行更深入的诊断。 - - 你需要按症状组织、结构稳定,并包含精确命令的运行手册章节。 -summary: Gateway 网关、渠道、自动化、节点和浏览器的深度故障排除手册 + - 故障排除中心已将你引导到这里,以便进行更深入的诊断 + - 你需要基于稳定症状的运行手册章节,并包含精确命令 +summary: Gateway 网关、渠道、自动化、节点和浏览器的深度故障排除运行手册 title: 故障排除 x-i18n: - generated_at: "2026-04-25T05:54:46Z" + generated_at: "2026-04-25T22:27:12Z" model: gpt-5.4 provider: openai - source_hash: c2270f05cf34592269894278e1eb75b8d47c02a4ff1c74bf62afb3d8f4fc4640 + source_hash: 801ad437164d4bd5b834e5018e4d73d452a61d6e6f084093bb736b4531c428c1 source_path: gateway/troubleshooting.md workflow: 15 --- # Gateway 网关故障排除 -本页是深度运行手册。 -如果你想先走快速分诊流程,请从 [/help/troubleshooting](/zh-CN/help/troubleshooting) 开始。 +此页面是深度运行手册。 +如果你想先使用快速分诊流程,请从 [/help/troubleshooting](/zh-CN/help/troubleshooting) 开始。 ## 命令阶梯 -先按以下顺序运行这些命令: +先运行这些命令,并按以下顺序执行: ```bash openclaw status @@ -32,13 +32,13 @@ openclaw channels status --probe 预期的健康信号: -- `openclaw gateway status` 显示 `Runtime: running`、`Connectivity probe: ok` 和一行 `Capability: ...`。 -- `openclaw doctor` 报告没有阻塞性的配置/服务问题。 -- `openclaw channels status --probe` 显示每个账号的实时传输状态,并在支持的情况下显示探测/审计结果,例如 `works` 或 `audit ok`。 +- `openclaw gateway status` 显示 `Runtime: running`、`Connectivity probe: ok`,以及一行 `Capability: ...`。 +- `openclaw doctor` 报告没有阻塞性的配置或服务问题。 +- `openclaw channels status --probe` 显示每个账户的实时传输状态,并且在支持的情况下,显示如 `works` 或 `audit ok` 之类的探测 / 审计结果。 -## Anthropic 429:长上下文需要额外配额 +## Anthropic 429:长上下文需要额外用量 -当日志/错误中包含以下内容时,使用本节: +当日志 / 错误中包含以下内容时使用本节: `HTTP 429: rate_limit_error: Extra usage is required for long context requests`。 ```bash @@ -47,30 +47,30 @@ openclaw models status openclaw config get agents.defaults.models ``` -请检查: +查找以下内容: -- 所选的 Anthropic Opus/Sonnet 模型是否设置了 `params.context1m: true`。 -- 当前的 Anthropic 凭证是否没有资格使用长上下文。 -- 请求是否仅在需要走 1M beta 路径的长会话/模型运行中失败。 +- 所选的 Anthropic Opus / Sonnet 模型设置了 `params.context1m: true`。 +- 当前的 Anthropic 凭证不具备长上下文用量资格。 +- 请求仅在需要使用 1M beta 路径的长会话 / 模型运行中失败。 修复选项: -1. 为该模型禁用 `context1m`,回退到普通上下文窗口。 -2. 使用有资格发起长上下文请求的 Anthropic 凭证,或切换到 Anthropic API key。 -3. 配置回退模型,这样在 Anthropic 长上下文请求被拒绝时,运行仍可继续。 +1. 对该模型禁用 `context1m`,回退到普通上下文窗口。 +2. 使用具备长上下文请求资格的 Anthropic 凭证,或切换为 Anthropic API key。 +3. 配置后备模型,以便在 Anthropic 长上下文请求被拒绝时,运行仍可继续。 相关内容: - [Anthropic](/zh-CN/providers/anthropic) -- [Token 使用和成本](/zh-CN/reference/token-use) +- [令牌使用与成本](/zh-CN/reference/token-use) - [为什么我会看到来自 Anthropic 的 HTTP 429?](/zh-CN/help/faq-first-run#why-am-i-seeing-http-429-ratelimiterror-from-anthropic) ## 本地 OpenAI-compatible 后端直接探测通过,但智能体运行失败 -当出现以下情况时,使用本节: +当出现以下情况时使用本节: -- `curl ... /v1/models` 正常 -- 很小的直接 `/v1/chat/completions` 调用正常 +- `curl ... /v1/models` 可正常工作 +- 很小的直接 `/v1/chat/completions` 调用可正常工作 - OpenClaw 模型运行仅在正常智能体轮次中失败 ```bash @@ -82,24 +82,24 @@ openclaw infer model run --model --prompt "hi" --json openclaw logs --follow ``` -请检查: +查找以下内容: -- 直接的小请求成功,但 OpenClaw 运行只在更大的提示词下失败 -- 后端报错 `messages[].content` 期望是字符串 -- 后端崩溃只出现在更大的提示 token 数或完整智能体运行时提示词下 +- 很小的直接调用成功,但 OpenClaw 运行仅在较大提示词下失败 +- 后端报错称 `messages[].content` 应为字符串 +- 后端仅在较大的提示词 token 数或完整智能体运行时提示词下崩溃 常见特征: -- `messages[...].content: invalid type: sequence, expected a string` → 后端拒绝结构化的 Chat Completions 内容片段。修复方式:设置 `models.providers..models[].compat.requiresStringContent: true`。 -- 很小的直接请求成功,但 OpenClaw 智能体运行因后端/模型崩溃而失败(例如某些 `inferrs` 构建上的 Gemma)→ OpenClaw 传输层很可能已经正确;失败的是后端在处理更大的智能体运行时提示词形态时崩溃。 -- 禁用工具后失败减少但未消失 → 工具 schema 确实增加了压力,但剩余问题仍然是上游模型/服务器容量限制或后端 bug。 +- `messages[...].content: invalid type: sequence, expected a string` → 后端拒绝结构化的 Chat Completions 内容分片。修复方法:设置 `models.providers..models[].compat.requiresStringContent: true`。 +- 很小的直接请求成功,但 OpenClaw 智能体运行因后端 / 模型崩溃而失败(例如某些 `inferrs` 构建中的 Gemma)→ OpenClaw 传输层很可能已经正确;失败的是后端在处理更大的 Agent Runtimes 提示词形态时出错。 +- 禁用工具后失败有所减少,但并未消失 → 工具 schema 是压力来源之一,但剩余问题仍然是上游模型 / 服务器容量限制或后端 bug。 修复选项: -1. 为仅支持字符串的 Chat Completions 后端设置 `compat.requiresStringContent: true`。 -2. 为无法可靠处理 OpenClaw 工具 schema 表面的模型/后端设置 `compat.supportsTools: false`。 -3. 在可能的情况下减轻提示词压力:更小的工作区引导、更短的会话历史、更轻量的本地模型,或改用长上下文支持更强的后端。 -4. 如果很小的直接请求持续通过,而 OpenClaw 智能体轮次仍在后端内部崩溃,请将其视为上游服务器/模型限制,并在上游提交一个包含已接受负载形态的复现。 +1. 对仅接受字符串的 Chat Completions 后端设置 `compat.requiresStringContent: true`。 +2. 对无法可靠处理 OpenClaw 工具 schema 表面的模型 / 后端设置 `compat.supportsTools: false`。 +3. 在可能的情况下减轻提示词压力:更小的工作区引导、更短的会话历史、更轻量的本地模型,或使用对长上下文支持更强的后端。 +4. 如果很小的直接请求持续通过,而 OpenClaw 智能体轮次仍在后端内部崩溃,则应将其视为上游服务器 / 模型限制,并向上游提交 repro,附上已被接受的负载形态。 相关内容: @@ -107,9 +107,9 @@ openclaw logs --follow - [配置](/zh-CN/gateway/configuration) - [OpenAI-compatible 端点](/zh-CN/gateway/configuration-reference#openai-compatible-endpoints) -## 没有回复 +## 无回复 -如果渠道在线但没有任何响应,在重新连接任何东西之前,先检查路由和策略。 +如果渠道已上线但没有任何响应,请在重新连接任何内容之前先检查路由和策略。 ```bash openclaw status @@ -119,17 +119,17 @@ openclaw config get channels openclaw logs --follow ``` -请检查: +查找以下内容: -- 私信发送者是否处于待配对状态。 +- 私信发送者的配对仍待处理。 - 群组提及门控(`requireMention`、`mentionPatterns`)。 -- 渠道/群组 allowlist 是否不匹配。 +- 渠道 / 群组 allowlist 不匹配。 常见特征: -- `drop guild message (mention required` → 群组消息在被提及之前会被忽略。 +- `drop guild message (mention required` → 群消息在被提及之前会被忽略。 - `pairing request` → 发送者需要批准。 -- `blocked` / `allowlist` → 发送者/渠道被策略过滤。 +- `blocked` / `allowlist` → 发送者 / 渠道被策略过滤。 相关内容: @@ -137,9 +137,9 @@ openclaw logs --follow - [配对](/zh-CN/channels/pairing) - [群组](/zh-CN/channels/groups) -## Dashboard / Control UI 连接问题 +## Dashboard 控制 UI 连接性 -当 dashboard/Control UI 无法连接时,检查 URL、认证模式和安全上下文假设。 +当 dashboard / 控制 UI 无法连接时,请验证 URL、认证模式和安全上下文假设。 ```bash openclaw gateway status @@ -149,36 +149,38 @@ openclaw doctor openclaw gateway status --json ``` -请检查: +查找以下内容: -- 探测 URL 和 dashboard URL 是否正确。 -- 客户端与 Gateway 网关之间的认证模式/token 是否不匹配。 -- 在需要设备身份的场景下是否使用了 HTTP。 +- 正确的探测 URL 和 dashboard URL。 +- 客户端与 Gateway 网关之间的认证模式 / token 不匹配。 +- 在需要设备身份时却使用了 HTTP。 常见特征: - `device identity required` → 非安全上下文,或缺少设备认证。 -- `origin not allowed` → 浏览器 `Origin` 不在 `gateway.controlUi.allowedOrigins` 中(或者你正在从非 loopback 浏览器来源连接,但没有显式 allowlist)。 -- `device nonce required` / `device nonce mismatch` → 客户端没有完成基于挑战的设备认证流程(`connect.challenge` + `device.nonce`)。 +- `origin not allowed` → 浏览器的 `Origin` 不在 `gateway.controlUi.allowedOrigins` 中(或者你正从非 loopback 的浏览器来源连接,但未显式加入 allowlist)。 +- `device nonce required` / `device nonce mismatch` → 客户端未完成基于质询的设备认证流程(`connect.challenge` + `device.nonce`)。 - `device signature invalid` / `device signature expired` → 客户端为当前握手签署了错误的负载(或使用了过期时间戳)。 -- `AUTH_TOKEN_MISMATCH` 且 `canRetryWithDeviceToken=true` → 客户端可以使用缓存的设备 token 执行一次受信任的重试。 -- 该缓存 token 重试会复用与配对设备 token 一起存储的缓存 scope 集合。显式 `deviceToken` / 显式 `scopes` 调用方则保留它们请求的 scope 集合。 -- 在该重试路径之外,连接认证优先级依次为:显式共享 token/password、显式 `deviceToken`、已存储的设备 token、bootstrap token。 -- 在异步 Tailscale Serve Control UI 路径上,相同 `{scope, ip}` 的失败尝试会在限流器记录失败之前串行化。因此,同一客户端两个错误的并发重试,第二次可能会显示 `retry later`,而不是两个普通的不匹配错误。 -- 来自浏览器来源 loopback 客户端的 `too many failed authentication attempts (retry later)` → 来自同一标准化 `Origin` 的重复失败会被临时锁定;另一个 localhost 来源会使用单独的 bucket。 -- 在该重试之后反复出现 `unauthorized` → 共享 token/设备 token 漂移;如有需要,请刷新 token 配置并重新批准/轮换设备 token。 -- `gateway connect failed:` → host/port/url 目标错误。 +- `AUTH_TOKEN_MISMATCH` 且 `canRetryWithDeviceToken=true` → 客户端可以使用缓存的设备 token 执行一次可信重试。 +- 该缓存 token 的重试会复用与已配对设备 token 一起存储的缓存作用域集合。显式 `deviceToken` / 显式 `scopes` 调用方则保持其请求的作用域集合不变。 +- 在该重试路径之外,连接认证优先级依次为:显式共享 token / 密码、显式 `deviceToken`、已存储设备 token、bootstrap token。 +- 在异步 Tailscale Serve Control UI 路径上,同一 `{scope, ip}` 的失败尝试会在限速器记录失败之前串行化。因此,同一客户端的两次并发错误重试中,第二次可能会显示 `retry later`,而不是两个普通的不匹配错误。 +- 浏览器来源的 loopback 客户端出现 `too many failed authentication attempts (retry later)` → 来自同一标准化 `Origin` 的重复失败会被临时锁定;另一个 localhost 来源使用的是单独的 bucket。 +- 在该重试之后仍重复出现 `unauthorized` → 共享 token / 设备 token 漂移;如有需要,刷新 token 配置,并重新批准 / 轮换设备 token。 +- `gateway connect failed:` → 主机 / 端口 / URL 目标错误。 ### 认证详细代码速查表 -使用失败的 `connect` 响应中的 `error.details.code` 来决定下一步操作: +使用失败 `connect` 响应中的 `error.details.code` 来选择下一步操作: -| 详细代码 | 含义 | 建议操作 | +| 详细代码 | 含义 | 推荐操作 | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `AUTH_TOKEN_MISSING` | 客户端没有发送必需的共享 token。 | 在客户端中粘贴/设置 token,然后重试。对于 dashboard 路径:`openclaw config get gateway.auth.token`,然后将其粘贴到 Control UI 设置中。 | -| `AUTH_TOKEN_MISMATCH` | 共享 token 与 Gateway 网关认证 token 不匹配。 | 如果 `canRetryWithDeviceToken=true`,允许执行一次受信任的重试。缓存 token 重试会复用已存储且已批准的 scopes;显式 `deviceToken` / `scopes` 调用方保留请求的 scopes。如果仍然失败,请运行 [token 漂移恢复清单](/zh-CN/cli/devices#token-drift-recovery-checklist)。 | -| `AUTH_DEVICE_TOKEN_MISMATCH` | 按设备缓存的 token 已过期或被撤销。 | 使用 [devices CLI](/zh-CN/cli/devices) 轮换/重新批准设备 token,然后重新连接。 | -| `PAIRING_REQUIRED` | 设备身份需要批准。检查 `error.details.reason` 是否为 `not-paired`、`scope-upgrade`、`role-upgrade` 或 `metadata-upgrade`,并在存在时使用 `requestId` / `remediationHint`。 | 批准待处理请求:`openclaw devices list`,然后 `openclaw devices approve `。在你审核请求的访问权限后,scope/role 升级也使用相同流程。 | +| `AUTH_TOKEN_MISSING` | 客户端未发送必需的共享 token。 | 在客户端中粘贴 / 设置 token 后重试。对于 dashboard 路径:`openclaw config get gateway.auth.token`,然后将其粘贴到 Control UI 设置中。 | +| `AUTH_TOKEN_MISMATCH` | 共享 token 与 Gateway 网关认证 token 不匹配。 | 如果 `canRetryWithDeviceToken=true`,允许一次可信重试。缓存 token 的重试会复用已存储的已批准作用域;显式 `deviceToken` / `scopes` 调用方保持请求的作用域不变。如果仍失败,请运行 [token 漂移恢复清单](/zh-CN/cli/devices#token-drift-recovery-checklist)。 | +| `AUTH_DEVICE_TOKEN_MISMATCH` | 每设备缓存 token 已过期或被撤销。 | 使用 [devices CLI](/zh-CN/cli/devices) 轮换 / 重新批准设备 token,然后重新连接。 | +| `PAIRING_REQUIRED` | 设备身份需要批准。请检查 `error.details.reason`,其值可能为 `not-paired`、`scope-upgrade`、`role-upgrade` 或 `metadata-upgrade`,并在存在时使用 `requestId` / `remediationHint`。 | 批准待处理请求:`openclaw devices list`,然后运行 `openclaw devices approve `。在你审查请求的访问权限后,作用域 / 角色升级也使用相同流程。 | + +使用共享 Gateway 网关 token / 密码进行认证的直接 loopback 后端 RPC,不应依赖 CLI 已配对设备的基础作用域。如果子智能体或其他内部调用仍然因 `scope-upgrade` 失败,请验证调用方使用的是 `client.id: "gateway-client"` 和 `client.mode: "backend"`,并且没有强制显式 `deviceIdentity` 或设备 token。 设备认证 v2 迁移检查: @@ -188,16 +190,16 @@ openclaw doctor openclaw gateway status ``` -如果日志显示 nonce/signature 错误,请更新正在连接的客户端,并验证它: +如果日志显示 nonce / signature 错误,请更新发起连接的客户端,并验证它: 1. 等待 `connect.challenge` 2. 对绑定 challenge 的负载进行签名 -3. 发送 `connect.params.device.nonce`,并使用相同的 challenge nonce +3. 使用相同的 challenge nonce 发送 `connect.params.device.nonce` 如果 `openclaw devices rotate` / `revoke` / `remove` 被意外拒绝: -- 配对设备 token 会话只能管理**它们自己的**设备,除非调用方还具有 `operator.admin` -- `openclaw devices rotate --scope ...` 只能请求调用方会话当前已经持有的 operator scopes +- 已配对设备 token 会话只能管理**它们自己的**设备,除非调用方还具有 `operator.admin` +- `openclaw devices rotate --scope ...` 只能请求调用方会话已持有的 operator 作用域 相关内容: @@ -216,23 +218,23 @@ openclaw gateway status openclaw status openclaw logs --follow openclaw doctor -openclaw gateway status --deep # 也会扫描系统级服务 +openclaw gateway status --deep # also scan system-level services ``` -请检查: +查找以下内容: -- `Runtime: stopped` 以及退出提示。 +- `Runtime: stopped`,并带有退出提示。 - 服务配置不匹配(`Config (cli)` 与 `Config (service)`)。 -- 端口/监听冲突。 -- 使用 `--deep` 时是否存在额外的 launchd/systemd/schtasks 安装。 +- 端口 / 监听器冲突。 +- 使用 `--deep` 时发现额外的 launchd / systemd / schtasks 安装。 - `Other gateway-like services detected (best effort)` 清理提示。 常见特征: -- `Gateway start blocked: set gateway.mode=local` 或 `existing config is missing gateway.mode` → 未启用本地 Gateway 网关模式,或者配置文件被覆盖并丢失了 `gateway.mode`。修复:在你的配置中设置 `gateway.mode="local"`,或者重新运行 `openclaw onboard --mode local` / `openclaw setup`,重新写入预期的本地模式配置。如果你通过 Podman 运行 OpenClaw,默认配置路径是 `~/.openclaw/openclaw.json`。 -- `refusing to bind gateway ... without auth` → 非 loopback 绑定时,没有有效的 gateway 认证路径(token/password,或在已配置情况下的 trusted-proxy)。 +- `Gateway start blocked: set gateway.mode=local` 或 `existing config is missing gateway.mode` → 未启用本地 Gateway 网关模式,或者配置文件被覆盖并丢失了 `gateway.mode`。修复方法:在你的配置中设置 `gateway.mode="local"`,或者重新运行 `openclaw onboard --mode local` / `openclaw setup`,以重新写入预期的本地模式配置。如果你通过 Podman 运行 OpenClaw,默认配置路径是 `~/.openclaw/openclaw.json`。 +- `refusing to bind gateway ... without auth` → 在没有有效 Gateway 网关认证路径的情况下绑定到非 loopback 地址(token / 密码,或在已配置时使用 trusted-proxy)。 - `another gateway instance is already listening` / `EADDRINUSE` → 端口冲突。 -- `Other gateway-like services detected (best effort)` → 存在陈旧或并行的 launchd/systemd/schtasks 单元。大多数部署应当每台机器只保留一个 Gateway 网关;如果你确实需要多个,请隔离端口 + 配置/状态/工作区。参见 [/gateway#multiple-gateways-same-host](/zh-CN/gateway#multiple-gateways-same-host)。 +- `Other gateway-like services detected (best effort)` → 存在过时或并行的 launchd / systemd / schtasks 单元。大多数设置应当每台机器只保留一个 Gateway 网关;如果你确实需要多个,请隔离端口 + 配置 / 状态 / 工作区。参见 [/gateway#multiple-gateways-same-host](/zh-CN/gateway#multiple-gateways-same-host)。 相关内容: @@ -240,9 +242,9 @@ openclaw gateway status --deep # 也会扫描系统级服务 - [配置](/zh-CN/gateway/configuration) - [Doctor](/zh-CN/gateway/doctor) -## Gateway 网关已恢复最后一次已知正确配置 +## Gateway 网关已恢复上次已知正常配置 -当 Gateway 网关能够启动,但日志显示它恢复了 `openclaw.json` 时,使用本节。 +当 Gateway 网关能够启动,但日志显示它恢复了 `openclaw.json` 时,请使用本节。 ```bash openclaw logs --follow @@ -251,21 +253,21 @@ openclaw config validate openclaw doctor ``` -请检查: +查找以下内容: - `Config auto-restored from last-known-good` - `gateway: invalid config was restored from last-known-good backup` - `config reload restored last-known-good config after invalid-config` -- 活动配置旁边是否存在带时间戳的 `openclaw.json.clobbered.*` 文件 -- 是否存在一条以 `Config recovery warning` 开头的主智能体系统事件 +- 活动配置旁边带时间戳的 `openclaw.json.clobbered.*` 文件 +- 以 `Config recovery warning` 开头的主智能体系统事件 发生了什么: -- 被拒绝的配置在启动或热重载期间未通过验证。 +- 被拒绝的配置在启动期间或热重载期间未通过验证。 - OpenClaw 将被拒绝的负载保留为 `.clobbered.*`。 -- 活动配置已从最后一次验证通过的最后一次已知正确副本恢复。 +- 活动配置已从上次验证通过的 last-known-good 副本中恢复。 - 下一次主智能体轮次会收到警告,不要盲目重写被拒绝的配置。 -- 如果所有验证问题都位于 `plugins.entries....` 之下,OpenClaw 不会恢复整个文件。插件本地失败会继续显式暴露,而不相关的用户设置会保留在活动配置中。 +- 如果所有验证问题都位于 `plugins.entries....` 之下,OpenClaw 不会恢复整个文件。插件本地失败会继续明确报出,而不相关的用户设置会保留在活动配置中。 检查并修复: @@ -279,18 +281,18 @@ openclaw doctor 常见特征: -- 存在 `.clobbered.*` → 外部直接编辑或启动时读取的内容已被恢复。 -- 存在 `.rejected.*` → 一次由 OpenClaw 发起的配置写入在提交前未通过 schema 或 clobber 检查。 -- `Config write rejected:` → 该写入尝试删除必需结构、大幅缩小文件,或持久化无效配置。 -- `missing-meta-vs-last-good`、`gateway-mode-missing-vs-last-good` 或 `size-drop-vs-last-good:*` → 启动时将当前文件视为被覆盖,因为与最后一次已知正确备份相比,它丢失了字段或体积变小。 -- `Config last-known-good promotion skipped` → 候选配置中包含已脱敏的密钥占位符,例如 `***`。 +- 存在 `.clobbered.*` → 外部直接编辑或启动读取的内容已被恢复。 +- 存在 `.rejected.*` → OpenClaw 自身发起的配置写入在提交前未通过 schema 或 clobber 检查。 +- `Config write rejected:` → 该写入尝试删除必需结构、显著缩小文件,或持久化无效配置。 +- `missing-meta-vs-last-good`、`gateway-mode-missing-vs-last-good` 或 `size-drop-vs-last-good:*` → 启动时将当前文件视为被覆盖,因为与 last-known-good 备份相比,它丢失了字段或大小发生了下降。 +- `Config last-known-good promotion skipped` → 候选内容包含已脱敏的密钥占位符,例如 `***`。 修复选项: -1. 如果恢复后的活动配置是正确的,就保留它。 -2. 仅从 `.clobbered.*` 或 `.rejected.*` 中复制你真正想要的键,然后用 `openclaw config set` 或 `config.patch` 应用。 +1. 如果恢复后的活动配置正确,就保留它。 +2. 仅从 `.clobbered.*` 或 `.rejected.*` 中复制你原本打算修改的键,然后通过 `openclaw config set` 或 `config.patch` 应用它们。 3. 重启前运行 `openclaw config validate`。 -4. 如果你手动编辑,请保留完整的 JSON5 配置,而不是只保留你想修改的部分对象。 +4. 如果你手动编辑,请保留完整的 JSON5 配置,而不是只保留你想更改的那部分对象。 相关内容: @@ -301,7 +303,7 @@ openclaw doctor ## Gateway 网关探测警告 -当 `openclaw gateway probe` 确实探测到了某些内容,但仍然打印出一段警告时,使用本节。 +当 `openclaw gateway probe` 能探测到某些目标,但仍打印警告块时,请使用本节。 ```bash openclaw gateway probe @@ -309,18 +311,18 @@ openclaw gateway probe --json openclaw gateway probe --ssh user@gateway-host ``` -请检查: +查找以下内容: - JSON 输出中的 `warnings[].code` 和 `primaryTargetId`。 -- 警告是否与 SSH 回退、多个 Gateway 网关、缺失 scopes,或未解析的认证引用有关。 +- 警告是否与 SSH 回退、多个 Gateway 网关、缺失作用域或未解析的认证引用有关。 常见特征: -- `SSH tunnel failed to start; falling back to direct probes.` → SSH 设置失败,但命令仍然尝试了直接配置目标/loopback 目标。 -- `multiple reachable gateways detected` → 有多个目标响应。通常这意味着有意的多 Gateway 网关部署,或存在陈旧/重复监听器。 -- `Read-probe diagnostics are limited by gateway scopes (missing operator.read)` → 连接成功了,但详细 RPC 受 scope 限制;请配对设备身份,或使用带有 `operator.read` 的凭证。 -- `Capability: pairing-pending` 或 `gateway closed (1008): pairing required` → Gateway 网关已响应,但该客户端在获得正常 operator 访问前仍需配对/批准。 -- 无法解析的 `gateway.auth.*` / `gateway.remote.*` SecretRef 警告文本 → 在该命令路径中,失败目标所需的认证材料不可用。 +- `SSH tunnel failed to start; falling back to direct probes.` → SSH 设置失败,但命令仍尝试了已配置的 / loopback 直接目标。 +- `multiple reachable gateways detected` → 有多个目标作出了响应。这通常意味着有意的多 Gateway 网关设置,或者存在过时 / 重复的监听器。 +- `Read-probe diagnostics are limited by gateway scopes (missing operator.read)` → 连接成功,但详细 RPC 受作用域限制;请配对设备身份,或使用具有 `operator.read` 的凭证。 +- `Capability: pairing-pending` 或 `gateway closed (1008): pairing required` → Gateway 网关已响应,但此客户端在获得正常 operator 访问前仍需要配对 / 批准。 +- 未解析的 `gateway.auth.*` / `gateway.remote.*` SecretRef 警告文本 → 在此次命令路径中,目标所需的认证材料不可用。 相关内容: @@ -328,9 +330,9 @@ openclaw gateway probe --ssh user@gateway-host - [同一主机上的多个 Gateway 网关](/zh-CN/gateway#multiple-gateways-same-host) - [远程访问](/zh-CN/gateway/remote) -## 渠道已连接,但消息不流动 +## 渠道已连接但消息未流动 -如果渠道状态显示已连接,但消息流是死的,请重点检查策略、权限和渠道特定的投递规则。 +如果渠道状态显示已连接,但消息流已中断,请重点检查策略、权限和渠道特定的投递规则。 ```bash openclaw channels status --probe @@ -340,17 +342,17 @@ openclaw logs --follow openclaw config get channels ``` -请检查: +查找以下内容: - 私信策略(`pairing`、`allowlist`、`open`、`disabled`)。 - 群组 allowlist 和提及要求。 -- 是否缺少渠道 API 权限/scopes。 +- 缺失的渠道 API 权限 / scopes。 常见特征: - `mention required` → 消息因群组提及策略而被忽略。 -- `pairing` / 待批准相关痕迹 → 发送者尚未获批。 -- `missing_scope`、`not_in_channel`、`Forbidden`、`401/403` → 渠道认证/权限问题。 +- `pairing` / 待批准痕迹 → 发送者尚未获批。 +- `missing_scope`、`not_in_channel`、`Forbidden`、`401/403` → 渠道认证 / 权限问题。 相关内容: @@ -361,7 +363,7 @@ openclaw config get channels ## Cron 和 heartbeat 投递 -如果 cron 或 heartbeat 没有运行,或没有成功投递,请先验证调度器状态,再检查投递目标。 +如果 cron 或 heartbeat 未运行或未投递,请先验证调度器状态,再检查投递目标。 ```bash openclaw cron status @@ -371,31 +373,31 @@ openclaw system heartbeat last openclaw logs --follow ``` -请检查: +查找以下内容: -- Cron 是否启用,以及是否存在下次唤醒时间。 -- 作业运行历史状态(`ok`、`skipped`、`error`)。 +- Cron 已启用,并且存在下次唤醒时间。 +- 任务运行历史状态(`ok`、`skipped`、`error`)。 - Heartbeat 跳过原因(`quiet-hours`、`requests-in-flight`、`alerts-disabled`、`empty-heartbeat-file`、`no-tasks-due`)。 常见特征: - `cron: scheduler disabled; jobs will not run automatically` → cron 已禁用。 -- `cron: timer tick failed` → 调度器 tick 失败;请检查文件/日志/运行时错误。 -- `heartbeat skipped` 且 `reason=quiet-hours` → 当前在活跃时间窗口之外。 -- `heartbeat skipped` 且 `reason=empty-heartbeat-file` → `HEARTBEAT.md` 存在,但只包含空行 / Markdown 标题,因此 OpenClaw 会跳过模型调用。 -- `heartbeat skipped` 且 `reason=no-tasks-due` → `HEARTBEAT.md` 包含一个 `tasks:` 块,但本次 tick 没有任何任务到期。 -- `heartbeat: unknown accountId` → heartbeat 投递目标的账号 id 无效。 -- `heartbeat skipped` 且 `reason=dm-blocked` → heartbeat 目标被解析为私信式目的地,而 `agents.defaults.heartbeat.directPolicy`(或按智能体覆盖项)被设置为 `block`。 +- `cron: timer tick failed` → 调度器 tick 失败;请检查文件 / 日志 / 运行时错误。 +- `heartbeat skipped` 且 `reason=quiet-hours` → 当前不在活跃时段窗口内。 +- `heartbeat skipped` 且 `reason=empty-heartbeat-file` → `HEARTBEAT.md` 存在,但只包含空行 / markdown 标题,因此 OpenClaw 会跳过模型调用。 +- `heartbeat skipped` 且 `reason=no-tasks-due` → `HEARTBEAT.md` 包含 `tasks:` 块,但在当前 tick 中没有任何任务到期。 +- `heartbeat: unknown accountId` → heartbeat 投递目标的账户 id 无效。 +- `heartbeat skipped` 且 `reason=dm-blocked` → heartbeat 目标被解析为私信式目的地,而 `agents.defaults.heartbeat.directPolicy`(或每个智能体的覆盖配置)被设置为 `block`。 相关内容: -- [计划任务:故障排除](/zh-CN/automation/cron-jobs#troubleshooting) -- [计划任务](/zh-CN/automation/cron-jobs) +- [定时任务:故障排除](/zh-CN/automation/cron-jobs#troubleshooting) +- [定时任务](/zh-CN/automation/cron-jobs) - [Heartbeat](/zh-CN/gateway/heartbeat) -## 已配对节点上的工具失败 +## 已配对节点的工具失败 -如果某个节点已配对,但工具失败,请分别排查前台状态、权限状态和批准状态。 +如果节点已配对但工具失败,请分别确认前台状态、权限状态和批准状态。 ```bash openclaw nodes status @@ -405,16 +407,16 @@ openclaw logs --follow openclaw status ``` -请检查: +查找以下内容: -- 节点是否在线,并具备预期能力。 -- 相机/麦克风/定位/屏幕的操作系统权限是否已授予。 +- 节点在线,并具备预期能力。 +- 相机 / 麦克风 / 位置 / 屏幕的 OS 权限授予状态。 - Exec 批准和 allowlist 状态。 常见特征: -- `NODE_BACKGROUND_UNAVAILABLE` → 节点应用必须位于前台。 -- `*_PERMISSION_REQUIRED` / `LOCATION_PERMISSION_REQUIRED` → 缺少操作系统权限。 +- `NODE_BACKGROUND_UNAVAILABLE` → 节点应用必须处于前台。 +- `*_PERMISSION_REQUIRED` / `LOCATION_PERMISSION_REQUIRED` → 缺少 OS 权限。 - `SYSTEM_RUN_DENIED: approval required` → exec 批准待处理。 - `SYSTEM_RUN_DENIED: allowlist miss` → 命令被 allowlist 阻止。 @@ -426,7 +428,7 @@ openclaw status ## 浏览器工具失败 -当 Gateway 网关本身健康,但浏览器工具操作仍然失败时,使用本节。 +当浏览器工具操作失败,但 Gateway 网关本身是健康的时,请使用本节。 ```bash openclaw browser status @@ -436,46 +438,46 @@ openclaw logs --follow openclaw doctor ``` -请检查: +查找以下内容: -- 是否已设置 `plugins.allow`,并且其中包含 `browser`。 -- 浏览器可执行文件路径是否有效。 -- CDP 配置文件是否可达。 -- 对于 `existing-session` / `user` 配置文件,本地 Chrome 是否可用。 +- 是否设置了 `plugins.allow`,并且其中包含 `browser`。 +- 有效的浏览器可执行文件路径。 +- CDP 配置文件可达性。 +- `existing-session` / `user` 配置文件所需的本地 Chrome 是否可用。 常见特征: -- `unknown command "browser"` 或 `unknown command 'browser'` → 内置 browser 插件被 `plugins.allow` 排除。 -- 当 `browser.enabled=true` 时 browser 工具缺失 / 不可用 → `plugins.allow` 排除了 `browser`,因此插件根本没有加载。 +- `unknown command "browser"` 或 `unknown command 'browser'` → 内置浏览器插件被 `plugins.allow` 排除。 +- 浏览器工具缺失 / 不可用,而 `browser.enabled=true` → `plugins.allow` 排除了 `browser`,因此插件从未加载。 - `Failed to start Chrome CDP on port` → 浏览器进程启动失败。 - `browser.executablePath not found` → 配置的路径无效。 - `browser.cdpUrl must be http(s) or ws(s)` → 配置的 CDP URL 使用了不受支持的协议,例如 `file:` 或 `ftp:`。 - `browser.cdpUrl has invalid port` → 配置的 CDP URL 端口无效或超出范围。 -- `Could not find DevToolsActivePort for chrome` → Chrome MCP existing-session 还无法附加到所选的浏览器数据目录。请打开浏览器的 inspect 页面,启用远程调试,保持浏览器打开,批准首次附加提示,然后重试。如果不需要登录状态,优先使用受管的 `openclaw` profile。 -- `No Chrome tabs found for profile="user"` → Chrome MCP 附加 profile 没有打开的本地 Chrome 标签页。 -- `Remote CDP for profile "" is not reachable` → 配置的远程 CDP 端点无法从 Gateway 网关主机访问。 -- `Browser attachOnly is enabled ... not reachable` 或 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile 没有可访问的目标,或者 HTTP 端点虽然有响应,但 CDP WebSocket 仍然无法打开。 -- `Playwright is not available in this gateway build; '' is unsupported.` → 当前 Gateway 网关安装缺少内置 browser 插件的 `playwright-core` 运行时依赖;运行 `openclaw doctor --fix`,然后重启 Gateway 网关。ARIA 快照和基础页面截图仍然可以使用,但导航、AI 快照、基于 CSS 选择器的元素截图以及 PDF 导出仍不可用。 -- `fullPage is not supported for element screenshots` → 截图请求同时使用了 `--full-page` 和 `--ref` 或 `--element`。 -- `element screenshots are not supported for existing-session profiles; use ref from snapshot.` → Chrome MCP / `existing-session` 的截图调用必须使用页面捕获或快照 `--ref`,而不是 CSS `--element`。 -- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP 上传钩子需要使用快照引用,而不是 CSS 选择器。 -- `existing-session file uploads currently support one file at a time.` → 在 Chrome MCP profiles 上,每次调用只发送一个上传文件。 -- `existing-session dialog handling does not support timeoutMs.` → Chrome MCP profiles 上的对话框钩子不支持超时覆盖。 -- `existing-session type does not support timeoutMs overrides.` → 对于 `profile="user"` / Chrome MCP existing-session profiles 上的 `act:type`,请省略 `timeoutMs`;如果需要自定义超时,请使用受管或 CDP 浏览器 profile。 -- `existing-session evaluate does not support timeoutMs overrides.` → 对于 `profile="user"` / Chrome MCP existing-session profiles 上的 `act:evaluate`,请省略 `timeoutMs`;如果需要自定义超时,请使用受管或 CDP 浏览器 profile。 -- `response body is not supported for existing-session profiles yet.` → `responsebody` 目前仍需要受管浏览器或原始 CDP profile。 -- attach-only 或远程 CDP profiles 上出现陈旧的 viewport / dark-mode / locale / offline 覆盖状态 → 运行 `openclaw browser stop --browser-profile `,关闭当前控制会话并释放 Playwright/CDP 模拟状态,而无需重启整个 Gateway 网关。 +- `Could not find DevToolsActivePort for chrome` → Chrome MCP existing-session 尚未成功附加到所选浏览器数据目录。打开浏览器检查页面,启用远程调试,保持浏览器开启,批准首次附加提示,然后重试。如果不需要登录状态,优先使用受管的 `openclaw` 配置文件。 +- `No Chrome tabs found for profile="user"` → Chrome MCP 附加配置文件没有打开的本地 Chrome 标签页。 +- `Remote CDP for profile "" is not reachable` → 配置的远程 CDP 端点从 Gateway 网关主机无法访问。 +- `Browser attachOnly is enabled ... not reachable` 或 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → 仅附加配置文件没有可访问目标,或者 HTTP 端点虽然有响应,但 CDP WebSocket 仍无法打开。 +- `Playwright is not available in this gateway build; '' is unsupported.` → 当前 Gateway 网关安装缺少内置浏览器插件所需的 `playwright-core` 运行时依赖;运行 `openclaw doctor --fix`,然后重启 Gateway 网关。ARIA 快照和基础页面截图仍可使用,但导航、AI 快照、基于 CSS 选择器的元素截图以及 PDF 导出仍不可用。 +- `fullPage is not supported for element screenshots` → 截图请求将 `--full-page` 与 `--ref` 或 `--element` 混用。 +- `element screenshots are not supported for existing-session profiles; use ref from snapshot.` → Chrome MCP / `existing-session` 截图调用必须使用整页捕获或快照 `--ref`,而不是 CSS `--element`。 +- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP 文件上传钩子需要使用快照引用,而不是 CSS 选择器。 +- `existing-session file uploads currently support one file at a time.` → 在 Chrome MCP 配置文件中,每次调用只能上传一个文件。 +- `existing-session dialog handling does not support timeoutMs.` → Chrome MCP 配置文件中的对话框钩子不支持超时覆盖。 +- `existing-session type does not support timeoutMs overrides.` → 在 `profile="user"` / Chrome MCP existing-session 配置文件上,对 `act:type` 省略 `timeoutMs`,或者在需要自定义超时时使用受管 / CDP 浏览器配置文件。 +- `existing-session evaluate does not support timeoutMs overrides.` → 在 `profile="user"` / Chrome MCP existing-session 配置文件上,对 `act:evaluate` 省略 `timeoutMs`,或者在需要自定义超时时使用受管 / CDP 浏览器配置文件。 +- `response body is not supported for existing-session profiles yet.` → `responsebody` 目前仍需要受管浏览器或原始 CDP 配置文件。 +- attach-only 或远程 CDP 配置文件上存在陈旧的视口 / 深色模式 / 区域设置 / 离线覆盖状态 → 运行 `openclaw browser stop --browser-profile `,关闭活动控制会话并释放 Playwright / CDP 仿真状态,而无需重启整个 Gateway 网关。 相关内容: - [浏览器故障排除](/zh-CN/tools/browser-linux-troubleshooting) - [浏览器(OpenClaw 托管)](/zh-CN/tools/browser) -## 如果你升级后突然出现问题 +## 如果你升级后突然出现故障 -大多数升级后的故障都与配置漂移或现在开始强制执行的更严格默认值有关。 +大多数升级后的故障都源于配置漂移,或是现在开始强制执行了更严格的默认值。 -### 1) 认证和 URL 覆盖行为已更改 +### 1) 认证和 URL 覆盖行为发生了变化 ```bash openclaw gateway status @@ -484,17 +486,17 @@ openclaw config get gateway.remote.url openclaw config get gateway.auth.mode ``` -检查项: +检查内容: -- 如果 `gateway.mode=remote`,CLI 调用可能会指向远程端,而你的本地服务其实是正常的。 -- 显式 `--url` 调用不会回退到已存储的凭证。 +- 如果 `gateway.mode=remote`,CLI 调用可能正在访问远程目标,而你的本地服务其实是正常的。 +- 显式 `--url` 调用不会回退到已存储凭证。 常见特征: - `gateway connect failed:` → URL 目标错误。 -- `unauthorized` → 端点可达,但认证错误。 +- `unauthorized` → 端点可访问,但认证错误。 -### 2) 绑定和认证护栏更严格了 +### 2) 绑定和认证保护措施变得更严格 ```bash openclaw config get gateway.bind @@ -504,17 +506,17 @@ openclaw gateway status openclaw logs --follow ``` -检查项: +检查内容: -- 非 loopback 绑定(`lan`、`tailnet`、`custom`)需要有效的 gateway 认证路径:共享 token/password 认证,或正确配置的非 loopback `trusted-proxy` 部署。 +- 非 loopback 绑定(`lan`、`tailnet`、`custom`)需要有效的 Gateway 网关认证路径:共享 token / 密码认证,或正确配置的非 loopback `trusted-proxy` 部署。 - 像 `gateway.token` 这样的旧键不会替代 `gateway.auth.token`。 常见特征: -- `refusing to bind gateway ... without auth` → 非 loopback 绑定缺少有效的 gateway 认证路径。 -- 运行时已启动,但 `Connectivity probe: failed` → Gateway 网关存活,但使用当前认证/url 无法访问。 +- `refusing to bind gateway ... without auth` → 非 loopback 绑定缺少有效的 Gateway 网关认证路径。 +- 运行时已启动但 `Connectivity probe: failed` → Gateway 网关存活,但使用当前 auth / URL 无法访问。 -### 3) 配对和设备身份状态已更改 +### 3) 配对和设备身份状态发生了变化 ```bash openclaw devices list @@ -523,17 +525,17 @@ openclaw logs --follow openclaw doctor ``` -检查项: +检查内容: -- dashboard/节点是否存在待批准的设备请求。 -- 策略或身份变化后,私信配对是否有待批准项。 +- dashboard / 节点存在待批准的设备请求。 +- 策略或身份变更后,存在待批准的私信配对请求。 常见特征: - `device identity required` → 设备认证未满足。 -- `pairing required` → 发送者/设备必须先获批。 +- `pairing required` → 发送者 / 设备必须先获批。 -如果完成以上检查后,服务配置和运行时仍然不一致,请使用相同的 profile/状态目录重新安装服务元数据: +如果在检查之后,服务配置与运行时仍然不一致,请从同一个配置文件 / 状态目录重新安装服务元数据: ```bash openclaw gateway install --force