执行审批

执行审批是伴侣应用/节点主机的安全护栏,控制沙箱化代理能否在真实主机(gatewaynode)上运行命令。可以理解为一道安全联锁:只有策略 + 允许列表 +(可选的)用户批准全部同意时,命令才被允许执行。执行审批是在工具策略和提权门控之外的额外检查(除非提权设为 full,那会跳过审批)。生效策略取 tools.exec.* 和审批默认值中更严格的那个;如果审批字段被省略,使用 tools.exec 的值。

如果伴侣应用 UI 不可用,任何需要提示的请求由 ask 回退决定(默认:拒绝)。

适用范围

执行审批在执行主机上本地强制执行:

  • 网关主机 → 网关机器上的 openclaw 进程
  • 节点主机 → 节点运行器(macOS 伴侣应用或无头节点主机)

信任模型说明:

  • 经网关认证的调用者是该网关的受信操作者。
  • 配对的节点将受信操作者能力扩展到节点主机上。
  • 执行审批降低意外执行风险,但不是按用户的认证边界。
  • 批准的节点主机运行绑定规范执行上下文:规范 cwd、精确 argv、存在时的环境绑定、适用时的固定可执行路径。
  • 对于 shell 脚本和直接解释器/运行时文件调用,OpenClaw 还会尝试绑定一个具体的本地文件操作数。如果该绑定文件在批准后、执行前发生变更,运行会被拒绝而非执行漂移的内容。
  • 这个文件绑定是尽力而为的,不是每个解释器/运行时加载器路径的完整语义模型。如果审批模式无法识别出恰好一个具体的本地文件来绑定,它会拒绝签发审批支持的运行,而不是假装完全覆盖。

macOS 分层:

  • 节点主机服务通过本地 IPC 将 system.run 转发给 macOS 应用
  • macOS 应用强制审批 + 在 UI 上下文中执行命令。

设置和存储

审批存储在执行主机上的本地 JSON 文件中:

~/.openclaw/exec-approvals.json

示例结构:

{
  "version": 1,
  "socket": {
    "path": "~/.openclaw/exec-approvals.sock",
    "token": "base64url-token"
  },
  "defaults": {
    "security": "deny",
    "ask": "on-miss",
    "askFallback": "deny",
    "autoAllowSkills": false
  },
  "agents": {
    "main": {
      "security": "allowlist",
      "ask": "on-miss",
      "askFallback": "deny",
      "autoAllowSkills": true,
      "allowlist": [
        {
          "id": "B0C8C0B3-2C2D-4F8A-9A3C-5A4B3C2D1E0F",
          "pattern": "~/Projects/**/bin/rg",
          "lastUsedAt": 1737150000000,
          "lastUsedCommand": "rg -n TODO",
          "lastResolvedPath": "/Users/user/Projects/.../bin/rg"
        }
      ]
    }
  }
}

策略开关

安全级别(exec.security

  • deny:阻止所有主机执行请求。
  • allowlist:仅允许在允许列表中的命令。
  • full:允许一切(等同于提权)。

Ask(exec.ask

  • off:从不提示。
  • on-miss:仅在允许列表不匹配时提示。
  • always:每次命令都提示。

Ask 回退(askFallback

如果需要提示但没有可达的 UI,回退策略决定:

  • deny:阻止。
  • allowlist:仅允许列表匹配时放行。
  • full:放行。

允许列表(按代理)

允许列表是按代理隔离的。如果有多个代理,在 macOS 应用中切换要编辑的代理。模式匹配是大小写不敏感的 glob 匹配。模式应该解析到二进制路径(仅基础名的条目会被忽略)。旧版 agents.default 条目在加载时会迁移到 agents.main

示例:

  • ~/Projects/**/bin/peekaboo
  • ~/.local/bin/*
  • /opt/homebrew/bin/rg

每个允许列表条目追踪:

  • id 稳定的 UUID,用于 UI 标识(可选)
  • 上次使用时间戳
  • 上次使用的命令
  • 上次解析的路径

自动允许技能 CLI

启用自动允许技能 CLI 后,已知技能引用的可执行文件在节点上(macOS 节点或无头节点主机)被视为已列入允许列表。这通过网关 RPC 的 skills.bins 获取技能二进制列表。如果你想要严格的手动允许列表,请禁用它。

重要的信任说明:

  • 这是一个隐式便捷允许列表,和手动路径允许列表条目是分开的。
  • 适用于网关和节点在同一信任边界内的受信操作者环境。
  • 如果你需要严格的显式信任,保持 autoAllowSkills: false 并只使用手动路径允许列表条目。

安全二进制(仅 stdin)

tools.exec.safeBins 定义了一小组仅 stdin 的二进制(比如 jq),可以在允许列表模式下运行而无需显式允许列表条目。安全二进制拒绝位置文件参数和路径样的令牌,所以只能操作输入流。把它当作流过滤器的窄通道快捷路径,而非通用信任列表。不要把解释器或运行时二进制(比如 python3noderubybashshzsh)加入 safeBins。如果命令设计上能执行代码、运行子命令或读取文件,优先使用显式允许列表条目并保持审批提示启用。自定义安全二进制必须在 tools.exec.safeBinProfiles.<bin> 中定义显式配置。验证完全基于 argv 形状(不做主机文件系统存在性检查),防止 allow/deny 差异泄露文件存在信息。文件导向的选项对默认安全二进制会被拒绝(比如 sort -osort --outputsort --files0-fromsort --compress-programsort --random-sourcesort --temporary-directory/-Twc --files0-fromjq -f/--from-filegrep -f/--file)。安全二进制还对破坏仅 stdin 行为的选项强制执行显式的每二进制标志策略(比如 sort -o/--output/--compress-program 和 grep 递归标志)。长选项在安全二进制模式下采用失败关闭验证:未知标志和歧义缩写会被拒绝。各安全二进制配置拒绝的标志:

  • grep: --dereference-recursive, --directories, --exclude-from, --file, --recursive, -R, -d, -f, -r
  • jq: --argfile, --from-file, --library-path, --rawfile, --slurpfile, -L, -f
  • sort: --compress-program, --files0-from, --output, --random-source, --temporary-directory, -T, -o
  • wc: --files0-from

安全二进制还强制在执行时将 argv 令牌视为字面文本(不做 glob 展开和 $VARS 扩展),防止用 *$HOME/... 之类的模式偷偷读取文件。安全二进制还必须从受信的二进制目录解析(系统默认值加上可选的 tools.exec.safeBinTrustedDirs)。PATH 条目永远不会被自动信任。默认受信安全二进制目录有意保持最小:/bin/usr/bin。如果你的安全二进制可执行文件在包管理器/用户路径下(比如 /opt/homebrew/bin/usr/local/bin/opt/local/bin/snap/bin),请显式添加到 tools.exec.safeBinTrustedDirs。允许列表模式下不自动允许 shell 链接和重定向。

Shell 链接(&&||;)在每个顶层段都满足允许列表(包括安全二进制或技能自动允许)时允许。重定向在允许列表模式下不受支持。命令替换($()/反引号)在允许列表解析时被拒绝,包括双引号内的;如果需要字面的 $() 文本,使用单引号。在 macOS 伴侣应用审批中,包含 shell 控制或扩展语法(&&||;|`$<>())的原始 shell 文本被视为允许列表未命中,除非 shell 二进制本身在允许列表中。对于 shell 包装器(bash|sh|zsh ... -c/-lc),请求范围的环境覆盖被缩减为一个小的显式允许列表(TERMLANGLC_*COLORTERMNO_COLORFORCE_COLOR)。对于允许列表模式下的始终允许决策,已知的分发包装器(envnicenohupstdbuftimeout)会持久化内部可执行路径而非包装器路径。Shell 多路复用器(busyboxtoybox)对 shell applet(shash 等)也会解包,持久化内部可执行文件而非多路复用器二进制。如果包装器或多路复用器无法安全解包,则不自动持久化允许列表条目。

默认安全二进制:jqcutuniqheadtailtrwc

grepsort 不在默认列表中。如果选择启用,为它们的非 stdin 工作流保留显式允许列表条目。在安全二进制模式下使用 grep 时,用 -e/--regexp 提供模式;位置模式形式被拒绝,防止文件操作数被伪装成歧义的位置参数。

安全二进制 vs 允许列表

主题tools.exec.safeBins允许列表(exec-approvals.json
目标自动允许窄范围的 stdin 过滤器显式信任特定可执行文件
匹配类型可执行文件名 + 安全二进制 argv 策略解析后的可执行路径 glob 模式
参数范围受安全二进制配置和字面令牌规则限制仅路径匹配;参数由你自行负责
典型示例jqheadtailwcpython3nodeffmpeg、自定义 CLI
最佳用途管道中的低风险文本转换任何有更广泛行为或副作用的工具

配置位置:

  • safeBins 来自配置(tools.exec.safeBins 或每代理的 agents.list[].tools.exec.safeBins)。
  • safeBinTrustedDirs 来自配置(tools.exec.safeBinTrustedDirs 或每代理的 agents.list[].tools.exec.safeBinTrustedDirs)。
  • safeBinProfiles 来自配置(tools.exec.safeBinProfiles 或每代理的 agents.list[].tools.exec.safeBinProfiles)。每代理的配置键覆盖全局键。
  • 允许列表条目位于主机本地的 ~/.openclaw/exec-approvals.json,在 agents.<id>.allowlist 下(或通过控制界面 / openclaw approvals allowlist ...)。
  • openclaw security audit 在解释器/运行时二进制出现在 safeBins 中但缺少显式配置时会发出 tools.exec.safe_bins_interpreter_unprofiled 警告。
  • openclaw doctor --fix 可以为缺失的自定义 safeBinProfiles.<bin> 条目生成 {} 骨架(之后检查并收紧)。解释器/运行时二进制不会被自动生成骨架。

自定义配置示例:

{
  tools: {
    exec: {
      safeBins: ["jq", "myfilter"],
      safeBinProfiles: {
        myfilter: {
          minPositional: 0,
          maxPositional: 0,
          allowedValueFlags: ["-n", "--limit"],
          deniedFlags: ["-f", "--file", "-c", "--command"],
        },
      },
    },
  },
}

控制界面编辑

使用控制界面 → Nodes → Exec approvals 卡片来编辑默认值、每代理覆盖和允许列表。选择范围(Defaults 或某个代理),调整策略,添加/移除允许列表模式,然后保存。UI 显示每个模式的上次使用元数据,方便你保持列表整洁。

目标选择器选择 Gateway(本地审批)或 Node。节点必须通告 system.execApprovals.get/set(macOS 应用或无头节点主机)。如果节点还未通告执行审批,直接编辑其本地的 ~/.openclaw/exec-approvals.json

CLI:openclaw approvals 支持网关或节点编辑(参见 审批 CLI)。

审批流程

当需要提示时,网关广播 exec.approval.requested 给操作者客户端。控制界面和 macOS 应用通过 exec.approval.resolve 解决它,然后网关将批准的请求转发给节点主机。

对于 host=node,审批请求包含规范的 systemRunPlan 负载。网关在转发批准的 system.run 请求时使用该计划作为权威的命令/cwd/会话上下文。

解释器/运行时命令

审批支持的解释器/运行时运行是有意保守的:

  • 精确的 argv/cwd/env 上下文始终被绑定。
  • 直接 shell 脚本和直接运行时文件形式会尽力绑定到一个具体的本地文件快照。
  • 常见的包管理器包装器形式如果仍然解析到一个直接本地文件(比如 pnpm execpnpm nodenpm execnpx),会在绑定前解包。
  • 如果 OpenClaw 无法为解释器/运行时命令识别出恰好一个具体的本地文件(比如包脚本、eval 形式、运行时特定的加载器链或歧义的多文件形式),审批支持的执行会被拒绝,而不是声称它没有的语义覆盖。
  • 对于这些工作流,优先使用沙箱、单独的主机边界,或操作者接受更广泛运行时语义的显式受信允许列表/full 工作流。

需要审批时,exec 工具会立即返回一个审批 ID。使用该 ID 关联后续系统事件(Exec finished / Exec denied)。如果在超时前没有收到决定,请求被视为审批超时并以拒绝原因呈现。

确认对话框包含:

  • 命令 + 参数
  • cwd
  • 代理 ID
  • 解析后的可执行路径
  • 主机 + 策略元数据

操作:

  • Allow once → 立即运行
  • Always allow → 加入允许列表 + 运行
  • Deny → 阻止

审批转发到聊天频道

你可以将执行审批提示转发到任何聊天频道(包括插件频道),然后用 /approve 批准。这使用正常的出站投递管道。

配置:

{
  approvals: {
    exec: {
      enabled: true,
      mode: "session", // "session" | "targets" | "both"
      agentFilter: ["main"],
      sessionFilter: ["discord"], // 子串或正则
      targets: [
        { channel: "slack", to: "U12345678" },
        { channel: "telegram", to: "123456789" },
      ],
    },
  },
}

在聊天中回复:

/approve <id> allow-once
/approve <id> allow-always
/approve <id> deny

内置聊天审批客户端

Discord 和 Telegram 也可以作为显式的执行审批客户端,有频道级配置。

  • Discord:channels.discord.execApprovals.*
  • Telegram:channels.telegram.execApprovals.*

这些客户端是选择启用的。如果频道没有启用执行审批,OpenClaw 不会仅因为对话发生在那里就把该频道当作审批面。

共同行为:

  • 只有配置的审批者可以批准或拒绝
  • 请求者不需要是审批者
  • 当频道投递启用时,审批提示包含命令文本
  • 如果没有操作者 UI 或配置的审批客户端能接受请求,提示回退到 askFallback

Telegram 默认向审批者发私信(target: "dm")。你可以切换到 channelboth 让审批提示也出现在发起的 Telegram 聊天/话题中。对于 Telegram 论坛话题,OpenClaw 会为审批提示和批准后的跟进保留话题。

参见:

macOS IPC 流程

Gateway -> Node Service (WS)
                 |  IPC (UDS + token + HMAC + TTL)
                 v
             Mac App (UI + approvals + system.run)

安全说明:

  • Unix socket 模式 0600,token 存储在 exec-approvals.json 中。
  • 同 UID 对等检查。
  • 挑战/响应(nonce + HMAC token + 请求哈希)+ 短 TTL。

系统事件

执行生命周期通过系统消息呈现:

  • Exec running(仅当命令超过运行通知阈值时)
  • Exec finished
  • Exec denied

这些在节点报告事件后发布到代理的会话。网关主机执行审批在命令完成时(以及可选地运行超过阈值时)发出相同的生命周期事件。审批门控的执行复用审批 ID 作为这些消息中的 runId,方便关联。

影响

  • full 权限很大;尽可能使用允许列表。
  • ask 让你保持知情,同时仍允许快速批准。
  • 每代理允许列表防止一个代理的审批泄露到其他代理。
  • 审批只适用于来自授权发送者的主机执行请求。未授权的发送者无法发出 /exec
  • /exec security=full 是授权操作者的会话级便捷功能,设计上跳过审批。要彻底阻止主机执行,把审批安全级别设为 deny 或通过工具策略拒绝 exec 工具。

相关文档: