📐 Harness 工程 · 中文翻译

10 安全与权限模型

安全机制的重要性与赋予智能体的自主性成正比。 最近的一脉学术工作把威胁模型形式化了:经文件或网页内容的间接提示词注入 [77]、作为注入攻防动态评测环境的 AgentDojo [76]、R-Judge [78] 之类的风险感知基准,以及 ToolSword [79] 的工具使用安全失败模式目录。 语料库覆盖了很宽的范围,从几乎没有安全控制的系统到多层架构。

10.1 Claude Code:三层权限系统

Claude Code 实现了架构上最优雅的安全系统,共三层(图 5):

Layer 3: Interactive User Dialog (approve / reject / edit)Layer 2: LLM-based Permission Classifier (allow / ask / deny)Layer 1: Static Hook Rules (PreToolUse pattern matching)Claude CodeSlowest, most reliableFastest, least context
图 5:Claude Code 的三层权限系统。

对后台与分叉的子智能体而言,只有第 1–2 层可用——它们的待发询问直接解析为拒绝——而默认的前台子智能体仍可浮出交互对话框。 无法解决的案例上报给父协调者。 一个拒绝跟踪机制按会话统计权限拒绝次数;超过 NN 次拒绝后,系统退回提示询问。 每个异步智能体维护本地拒绝状态,防止跨智能体污染。

10.2 Codex:带原生沙箱的四层权限栈

4 月版把 Codex 的安全描述为两种机制——策略规则加操作系统沙箱——并把它的审批门形容为“几乎不可见”。 7 月快照显示有四层,其中两层收敛到 Claude Code 的设计:

第 1 层:执行策略(Starlark,不是 TOML)。

可执行规则(execpolicy/)用 Starlark 编写:prefix_rule(pattern=[…], decision="allow|prompt|forbidden", match=[…], not_match=[…]) 与 network_rule(…) 函数,从 CODEX_HOME/rules/ 和各配置层规则目录加载。7774 月版把这些规则呈现为 TOML;那是我们早期审计的一个错误——策略语言一直都是 Starlark。 一个有特色的细节:规则可携带内联的 match/not_match 示例,并在解析时校验——策略文件里的可执行测试用例。

1prefix_rule(
2pattern=["git","status"],
3decision="allow",
4match=[["git","status"],["git","status","--short"]],
5not_match=[["git","push"]],
6)
7network_rule(
8protocol="https",
9host="*.github.com",
10decision="allow",
11)
清单 2:Codex 执行策略示例(Starlark)。
第 2 层:生命周期 Hook。

一个 hooks crate 暴露外部 Hook,其事件词汇几乎逐字照搬 Claude Code:PreToolUse、PermissionRequest、PostToolUse、PreCompact、SessionStart、UserPromptSubmit、SubagentStart、SubagentStop、Stop——外加一个 PostCompact 事件(Claude Code 没有对应物)——带 block/allow 决策输出。 第 14.5 节将把它作为语料库中最清晰的案例来讨论:一个厂商原生 Harness 把另一个的扩展接口当作事实标准采纳。

第 3 层:Guardian,一个 LLM 审批审查器。

当一条命令需要用户批准时,一个专门的 Guardian 会话依据策略提示词重新评估确切的计划动作(紧凑转录重建、严格 JSON 裁决),超时或输出畸形时失败即关闭(fail closed),并带每轮拒绝熔断器。 4 月版对比 Claude Code 画出的“没有 LLM 分类器”反差不再成立:两个厂商原生旗舰如今都实现了静态规则 →\to LLM 分类器 →\to 交互/操作系统兜底的模式。 一个面向用户的协作模式选择器(Plan/Default 预设,遮蔽模型、推理力度与开发者指令)完成了趋同:四个厂商原生系统现在都随附只读规划模式。

第 4 层:原生操作系统沙箱。

沙箱实现横跨三个平台:

  • •

    Linux:源内 vendored 的 Bubblewrap(经 C FFI 调用),只读文件系统(--ro-bind / /)、经 --bind 的可写根、网络命名空间隔离(--unshare-net)、用户/PID 命名空间隔离;Landlock 降级为旧版回退。

  • •

    macOS:经 /usr/bin/sandbox-exec 的 Seatbelt 配置,带可配置的允许/拒绝规则。

  • •

    Windows:受限令牌进程,配基于 ACL 的读写限制。

观察 6。操作系统级沙箱是语料库中代码成本最高的能力之一,而且它是一种选择,不是规模的后果。4 月的语料库暗示过规模相关性(其中最大的两个系统恰是它的两个跨平台沙箱实现者);扩大的语料库打破了它。Hermes 是这里最大的系统之一,却不带任何操作系统级隔离原语:它把封禁委托给六个可插拔执行后端,而把安全预算花在内容型威胁上(提示词恶意软件扫描——对提示词注入载荷做模式匹配——技能供应链、一个在 --yolo 下仍然存活的命令策略底线)。OpenCode 体量相当,却仅用策略,把投入放在语法感知的命令权限控制而非隔离上。Pi 把拒绝写成安全论证:进程内部分沙箱“很容易被误解为安全边界”。仍然成立的是成本一侧:凡是构建了原生沙箱的地方(Codex、Gemini CLI;Claude Code 把 Anthropic 可复用的 sandbox-runtime 包成可选件),都是数千行级别的可观投入——第 14.4 节将展示元 Harness 在高一层又付了一次同样的账单。

10.3 OpenHands:集合式的纵深防御

OpenHands 的可插拔 SecurityAnalyzer 框架在 V1 SDK 中显著成熟。 V0 时代的 Invariant 分析器已消失;现役组合是一对 LLMSecurityAnalyzer(智能体给每个动作的 security_risk 自评分,系统提示词指示它填写该参数)与 GraySwanAnalyzer(外部对抗 API),加上两个新的确定性分析器——PatternSecurityAnalyzer 与 PolicyRailSecurityAnalyzer,后者在 shell AST 解析之上随附命名护栏(named rails),如 fetch-to-exec、raw-disk-op 与 catastrophic-delete。 一个 EnsembleSecurityAnalyzer 以“最坏者胜出”融合各裁决,坏掉的子分析器一律按 HIGH 关闭处理。 LOW/MEDIUM/HIGH/UNKNOWN 风险枚举保留;确认现在是一个策略对象(AlwaysConfirm/NeverConfirm/ConfirmRisky)。 提示词一侧补齐了双向的注入防御:仓库来源的上下文被包在 <UNTRUSTED_CONTENT> 标记里,一个专门的提示词节教授风险评估协议。

10.4 OpenClaw:基于作用域的授权

OpenClaw 在命名空间化的作用域(operator.read/write/admin/pairing/…)上,用 operator 与 node 连接角色实现基于作用域的授权。 网关按方法强制作用域要求。 其他安全机制包括:按 IP/令牌的固定窗口速率限制、SSRF 策略强制、带配对审批工作流的私聊白名单、浏览器动作与插件动作的执行审批门,以及聊天内容净化。 2MB 的 MAX_PROMPT_BYTES 限制提供 DoS 防护(CWE-400)。

10.5 Gemini CLI:四种审批模式加跨平台沙箱

Gemini CLI 叠加两种互补的安全机制。 第一,一个 ApprovalMode 枚举把每次工具调用门控进四种模式之一:

  • •

    PLAN:只读;模型看到完整工具列表,但只能调用读工具(Glob、Read、Grep 等)。它的响应以计划形式呈现,用户必须显式批准才能退出 plan 模式。

  • •

    DEFAULT:每次工具调用弹出交互审批对话框;用户可以批准一次、总是批准或拒绝。

  • •

    AUTO_EDIT:编辑操作自动批准,而 shell 及其他有副作用的工具仍需询问;用于本地代码的快速迭代。

  • •

    YOLO:所有动作自动批准。仅面向 CI/脚本用途。

第二,一个 SandboxPolicyManager 强制基于 TOML 的分模式策略:哪些路径可读/可写、哪些网络主机可达、哪些环境变量被清洗。 这一组合在结构上类似于 Codex 的“策略即代码 + 沙箱”栈,但其上再叠一个显式的面向用户的模式选择器——一项人体工学设计,Codex 后来也以协作模式预设采纳了它。 一个独立的 isTrustedFolder() 检查进一步按目录是否在用户信任清单中来扩大或收窄上下文发现范围,提供第四层可选粒度。 我们两次快照之间的发布节奏由策略引擎与供应链加固主导——无头模式下受信任门控的 .env 加载、带核心工具白名单的 shell 命令校验、技能安装的路径穿越检查——支持观察 10.2 的论断:在最大的系统里,安全吸收了不成比例的工程投入。

10.6 Mistral Vibe:权限作用域模式加智能体档案门控

Mistral Vibe 没有操作系统沙箱(可选的 --worktree 标志如今提供分支级隔离),但用比其他无沙箱系统更细粒度的权限模型来补偿。 每次工具调用按一个层级检查:

  1. 1.

    智能体档案级的工具级 permission 设置(ALWAYS、ASK、NEVER)。

  2. 2.

    工具专属校验器(如 resolve_file_tool_permission 对路径做模式匹配),外加一个默认的只读命令白名单,自动批准 ls/cat/grep 类命令。

  3. 3.

    用户声明的 shell Hook(hooks.toml、before_tool),可在权限评估之前拒绝调用或改写其输入。

  4. 4.

    运行时添加的会话规则——“总是允许”的授予现在跨会话持久化。

  5. 5.

    除非设置了 bypass_tool_permissions(更名后的 auto_approve),否则向用户呈现交互式审批回调。

智能体档案烘焙进安全分级:plan 与 chat 档案是 SAFE(只读);default 是 NEUTRAL;accept-edits 是 DESTRUCTIVE;auto-approve 是 YOLO。 工具也可以覆盖智能体默认值:无论档案如何,write_file 对敏感模式(.env 文件)强制 ASK。 没有基于 LLM 的风险分类器,也没有操作系统级隔离;安全归结为显式的逐模式匹配、Hook 与用户询问。

10.7 Hermes:一个在 YOLO 下仍然存活的策略底线

Hermes 把沙箱问题反了过来:语料库中最大的 Python 系统不带任何操作系统级隔离原语——工具树里找不到 Seatbelt、Landlock、seccomp 或 Bubblewrap——把隔离委托给它的六个可插拔执行后端。 在本地后端上,安全是规模化后的策略即代码:一个 3,200 行的审批模块,其文档写道“config.yaml 就是安全策略”。 它的层:用户拒绝 glob;一个 12 模式的硬底线(rm -rf /、mkfs、对块设备的 dd、fork 炸弹、关机),在 --yolo 下仍然存活——YOLO 环境变量恰好在模块导入时被冻结,免得被提示词注入的技能在运行时翻转;47 个危险命令模式,在去混淆变体上匹配(去除引号拼接、折叠命令替换、锚定命令位);一个外部 Rust 内容扫描器(Tirith,安装经 cosign 验证);以及一个可选的辅助 LLM 门(_smart_approve:temperature 0、最多 16 token、APPROVE/DENY/ESCALATE——其代码致谢 Codex 的 Smart Approvals)。 它的特色威胁模型是内容型的:对上下文文件、记忆写入、MCP 工具描述与技能安装的提示词恶意软件扫描(带 builtin/trusted/community 信任分级与隔离区);始终封锁云元数据端点的 SSRF 守卫;不可信工具结果包进 <untrusted_tool_result> 定界符并做形似字符消毒。 容器后端完全跳过危险命令层——直到主机 bind-mount 重新进入其中。 显著的缺席:没有逐工具的允许/询问/拒绝矩阵,没有只追加的审计日志。

10.8 Pi:把缺席写成安全论证

Pi 是语料库中唯一把安全基础设施的缺席写为设计原则的系统:其安全文档论证进程内部分沙箱“很容易被误解为安全边界”,宣告经上下文文件的提示词注入不可防护,并让内建工具以调用者用户的权限无条件执行。 唯一的内建门是项目信任:仓库控制的配置(扩展、技能、提示词、主题)只从受信任路径加载,按规范化路径以最近祖先查找决定——明确“不是沙箱”,而上下文文件无条件加载。 权限控制是字面意义的策略即代码:tool_call 扩展事件暴露可变的工具参数与一个 {block, reason} 否决;参考示例 permission-gate 用约 ∼\sim80 行用户空间代码实现了熟悉的“正则加确认”流(rm -rf、sudo、chmod 777);需要隔离时,扩展前来(Anthropic 的 sandbox-runtime、一个 QEMU 微 VM),经逐工具的 Operations 接缝接入。 只追加的会话树兼任完整的审计轨迹。

10.9 OpenCode:语法感知的权限控制,默认宽松

继 Hermes 之后,OpenCode 是第二大不带操作系统级隔离的系统(代码中的“sandbox”指 git worktree),其默认姿态是 Codex 的反面:项目之内 "*": allow,询问只保留给 external_directory 访问、.env 读取和死循环。 它独有的投入是语法感知的命令权限控制:每条 bash 命令都经 web-tree-sitter 解析(bash 与 PowerShell 文法);确切的命令文本成为询问模式,而“总是允许”的授予由一个约 130 条、明确标注为 LLM 生成的命令元数(arity)字典界定(git→\to2、npm run→\to3),产出诸如 git commit * 而非一揽子批准的授权;改文件的命令会解析其参数路径,项目外路径引发 external_directory 询问。 权限规则({permission, pattern, action},glob 通配上后匹配胜出)按 默认 →\to 内建智能体 →\to 用户配置 →\to 每智能体 →\to 每会话分层;把某工具的 "*" 设为拒绝会把它从 LLM 视野中整个移除——工具可用性本身就是权限的派生物。 一个平行的 v2 引擎反转为默认拒绝,并把批准持久化到 SQLite;无头运行自动拒绝一切询问。 没有危险命令拒绝清单,也没有风险分类器。

10.10 极简安全(Aider、Mini-SWE-Agent)

Aider 提供交互式确认模式,但没有自动化风险评估。 不过,带三阶段 Python lint 的反思循环(语法 →\to 编译 →\to flake8)通过在错误传播前捕获它们,提供了隐式安全。

Mini-SWE-Agent 只实现资源限制作为安全机制——step_limit、cost_limit,以及(v2.4 线新增)真实时钟限制和连续格式错误上限,外加可选的交互确认模式——对基准评测足够,对生产使用不足。