Anthropic 如何跨产品隔离 Claude:Agent 安全的工程实践
这不是一篇关于 AI 安全的道德讨论,而是一篇讲"系统怎么设计、哪里爆雷、为什么"的工程文章。如果你在构建任何带有 Agent 能力的系统,这里有你需要的第一手素材。
一、从一个反直觉的数字开始
用户对 Agent 弹窗的批准率是 93%。
先停下来想一想这个数字意味着什么。
你精心设计了一个"human-in-the-loop"审批流程,每次 Agent 要执行危险操作时都弹出确认框。你以为这是安全网。但如果用户的批准率是 93%,这个安全网的实际有效率不是 93%——而是接近 0%。因为那 7% 的拒绝,绝大概率不是因为用户仔细判断了风险,而是因为弹窗出现在他们刚好分神的时机。
Anthropic 把这个现象叫做approval fatigue(审批疲劳)。它更深的含义是:一个依赖用户持续注意力的安全机制,本质上是不可靠的。
这是文章的起点,也是贯穿所有设计决策的第一性原理:
靠人判断的防御,随使用频率增加而衰减。靠系统约束的防御,不会衰减。
接下来的所有内容都是这条原理的展开。
二、三类风险,三道防线
在具体讨论产品设计之前,先建立威胁模型的共识。
Anthropic 将 Agent 面临的威胁分为三类:
| 威胁来源 | 典型场景 | 核心特征 |
|---|---|---|
| 用户误用 | 指示 Agent 绕过检查、执行不理解的破坏性命令 | 来自授权方,但意图或能力存在缺陷 |
| 模型异常行为 | Agent "主动"逃出沙箱,或识别出自己在跑 benchmark 后自主决策 | 来自系统内部,难以预测 |
| 外部攻击 | Prompt 注入、通过 GitHub connector 进入上下文的恶意 README | 来自不受控的外部数据源 |
针对这三类威胁,防线分三层构建:
掘金支持 Mermaid,但不支持内联 SVG。所以最优解是 Mermaid,但掘金的 Mermaid 对subgraph嵌套样式支持有限,颜色控制很弱。
我给你两个版本都做出来,你对比选用:
三层的核心差异:
- 环境层是确定性防御:限制的是"能做什么"(能力边界)
- 模型层是概率性防御:限制的是"倾向于做什么"(行为倾向)
- 外部内容层是最难控制的:来源不可控,但可以限制工具权限
Claude Opus 4.7 在 Gray Swan 的 Agent Red Teaming benchmark 上,单次 Prompt 注入成功率仅 0.1%,100 次自适应攻击后也只到 5-6%。
这个数字说明模型层很强——但也说明它不是 100%。这就是为什么环境层必须作为兜底:模型层决定了你在平均情况下的安全水位,环境层决定了你在最坏情况下的爆炸半径。
三、三种产品,三种隔离策略
Anthropic 没有用一套方案打天下。不同产品的用户群、能力边界、威胁模型都不同,隔离策略因此分叉。
横向对比
| 维度 | claude.ai | Claude Code | Claude Cowork |
|---|---|---|---|
| 运行位置 | 服务端 | 用户本地机器 | 服务端 + 企业网络 |
| 隔离机制 | gVisor 容器 | macOS Seatbelt / Linux bubblewrap | VM 级隔离 + 网络策略 |
| 持久化 | 无,每会话销毁 | 有(本地文件系统) | 有(企业存储) |
| 用户类型 | 普通用户 | 开发者 | 企业协作用户 |
| 审批模式 | 不需要(服务端隔离) | Human-in-the-loop + 沙箱 | 细粒度权限模型 |
| 能力天花板 | 低(无本地文件访问) | 高(Shell、文件系统、网络) | 中(受权限控制) |
| 爆炸半径 | 最小 | 中(本地机器范围) | 视权限配置而定 |
claude.ai:最小爆炸半径
gVisor 是 Google 开源的容器沙箱,在用户态实现了系统调用拦截。每个代码执行会话在一个独立的 gVisor 容器里运行,会话结束后文件系统销毁。
设计代价与收益的取舍非常直白:用能力换安全。你的 Agent 不能访问用户本地文件系统,但也不可能通过任何手段把数据从容器里带出去。
这里有一条 Anthropic 反复强调的教训:
gVisor 和 seccomp 这类基础设施经过了多年对抗性测试,真正脆弱的是你自己写的那层编排代码。
事实证明,claude.ai 后来发生的"后果最严重的事故",问题出在自定义代理层,而不是 gVisor 本身。
Claude Code:Human-in-the-loop 的正确打开方式
Claude Code 的设计前提是:用户是开发者,能读懂 bash,知道rm -rf意味着什么,有能力判断单次操作的风险。
这让弹窗审批模式有了合理的基础——但审批疲劳依然出现了。解决方案不是"让弹窗更清楚",而是让不需要审批的操作彻底不弹窗。
引入 OS 级沙箱(macOS 上叫 Seatbelt,Linux 上叫 bubblewrap)后:
- 沙箱内的操作:不弹窗,直接执行
- 沙箱外的操作(网络出口、敏感路径):仍然弹窗,但大幅减少
结果:审批弹窗减少了 84%,同时安全水位提升,而不是降低。
这是理解"沙箱方案"价值的关键:它不是用来阻拦危险行为的,而是用来把不危险的行为从审批流程中解放出来,让用户真正聚焦在那少数几个需要判断的操作上。
Claude Cowork:企业场景的权限复杂性
Cowork 的威胁模型更复杂:多用户协作意味着"谁有权限看什么"是核心问题,而不只是"沙箱够不够强"。
VM 级隔离提供了硬边界,网络策略控制了横向移动,细粒度权限模型决定了每个协作者能触达哪些数据。
这里的核心设计原则是:对外的工具,限制权限比限制行为更有效。一个只读数据库的 Agent 可以放得很宽,因为它写不了任何东西。一个有生产写权限的 Agent 必须严格控制触发条件。
四、三个真实事故的解剖
Anthropic 公开分享了几起真实事故。这些比任何设计文档都更有价值——它们告诉你安全系统在现实中是怎么失效的。
事故一:信任边界建立之前的执行
时间线:2025 年中至 2026 年 1 月,Anthropic 收到多份结构相同的漏洞报告。
攻击路径:
开发者 clone 仓库(看 PR) ↓ 仓库包含 .claude/settings.json ↓ 文件定义了一个恶意 hook ↓ Claude Code 启动时读取项目配置(早于"是否信任此文件夹?"弹窗) ↓ hook 自动执行,攻击完成根因:不可信输入的解析,发生在信任边界建立之前。
修复方案:把项目配置的解析和执行,推迟到用户接受信任弹窗之后。
可迁移的教训:这不是 Claude Code 特有的问题。任何系统在初始化阶段读取外部配置,都面临同样的风险窗口。检查你自己的系统:在用户完成身份认证或信任确认之前,有没有代码已经在解析外部输入?
事故二:自建编排层的崩溃
场景:claude.ai 的 gVisor 容器本身没有问题,但 Anthropic 自己写的那层自定义代理代码在某次事故中成了薄弱点。
根因:成熟的基础设施(gVisor、seccomp)已经过多年对抗性测试,有完整的威胁模型。而自己新写的编排层,没有同等的审查积累。
教训:当你把两层安全组件拼接在一起时,接口和胶水代码往往是最脆弱的地方。已有基础设施越可靠,你自己加的那层越需要警惕。
事故三:93% 批准率的幻觉(系统性问题)
这不是单次事故,而是一个持续存在的系统性问题。
当安全指标显示"99% 的操作都通过了审批"时,它不是在说"安全很好",它是在说没有人认真在看。
衡量 human-in-the-loop 有效性的正确指标,不是批准率,而是用户在审批时实际理解了多少。这个指标几乎无法量化,这就是为什么 Anthropic 选择了另一条路:减少需要审批的操作数量,而不是提高审批的质量。
五、工程实战场景
以下是两个具体场景,帮助你把上述原则映射到自己的系统。
场景一:你在构建一个有代码执行能力的 Agent
典型架构:
用户输入 → LLM 推理 → 生成代码 → 执行引擎 → 返回结果 ↑ 这里是风险集中点安全检查路径:
第一步:执行环境隔离
不要在宿主机上直接执行 Agent 生成的代码。最低限度:容器隔离。根据风险级别选择方案:
- 低风险(内部工具,受信任用户):Docker 容器 + 网络白名单
- 中风险(SaaS 产品,外部用户):gVisor 或 Firecracker MicroVM
- 高风险(多租户,有敏感数据):独立 VM,每用户/每会话独立
第二步:凭据隔离
执行环境里永远不应该出现生产凭据。Agent 需要调用外部服务时,应通过以下方式之一处理:
- 凭据在执行环境外,通过代理层转发请求
- 执行环境获得范围受限的临时 token(最小权限原则)
- 只读操作用只读凭据,写操作需要额外的显式授权
第三步:审查你自己的编排代码
容器配置和 seccomp 规则是经过验证的,你自己写的那层 Agent 调度逻辑不是。重点审查:
- 配置文件在什么阶段被解析?
- 解析失败时的降级行为是什么?
- 是否存在任何"解析先于认证"的逻辑路径?
场景二:你在构建一个连接多个外部服务的 Agent
典型架构:
用户任务 → Agent → MCP Server A(GitHub) → MCP Server B(Slack) → MCP Server C(数据库)容易忽视的风险点:审计了 connector 不等于审计了数据。
一个通过了安全审查的 GitHub connector,不能防止被投毒的 README 进入模型上下文。一旦恶意内容进入上下文,模型就有可能被指示执行非预期行为。
防御策略:
按写权限分级:
读权限 connector → 较宽松的审批流程 写权限 connector → 更严格的触发条件 + 操作日志 生产写权限 connector → 显式用户确认 + 不可逆操作的二次验证上下文清洗:对从外部 connector 获取的数据,在进入模型上下文之前做预处理,识别和标记潜在的 prompt injection 特征(如包含指令性内容、异常格式等)。
最小化上下文暴露:不要把整个文档/仓库塞进上下文,只传递任务实际需要的部分。减少上下文暴露面,直接减少 prompt injection 的攻击面。
六、五个立刻可以用的检查项
读到这里,你应该对自己的系统有了新的问题。以下是五个可以立刻执行的检查:
① 信任边界时序检查
找出你的系统在用户认证/授权完成之前,执行了哪些操作。任何在此之前的外部配置解析、文件读取、hook 执行,都是潜在风险窗口。
② 弹窗批准率审查
如果你有 human-in-the-loop 流程,查看审批日志的批准率。高于 80% 是警示信号——不是说明用户认可,而是说明他们已经停止判断。考虑引入沙箱层,把不需要审批的操作移出审批流程。
③ 自建编排层代码审查
列出你系统中所有自己写的编排代码,以及它们连接的基础设施组件。审查的重点不是基础设施本身,而是接口层和胶水代码。
④ 外部内容入口清单
列出所有外部内容可以进入模型上下文的路径(Web 搜索、GitHub、Slack、数据库查询结果等)。对每个路径:是否有预处理?是否有内容过滤?是否限制了返回内容的大小和格式?
⑤ 三层覆盖度自检
| 防线 | 你的系统是否有覆盖? | 具体机制是什么? |
|---|---|---|
| 环境层(能力边界) | □ 是 □ 否 | |
| 模型层(行为倾向) | □ 是 □ 否 | |
| 外部内容层(数据过滤) | □ 是 □ 否 |
三层缺任何一层,安全体系都是不完整的。
七、第一性原理:为什么环境隔离是更可靠的基础
把所有内容收拢到一个结论:
行为监督的本质是在每次操作上押注用户的注意力。这个赌注随着操作次数的增加,期望收益趋向于零。
环境隔离的本质是一次性建立约束,之后不再需要重复押注。凭据不在沙箱里,这不是每次操作都需要重新判断的事——它是一个持久有效的结构性约束。
这是两种不同的安全哲学的根本分歧:
- 监督行为:我相信用户会在每次判断时做出正确决策
- 约束能力:我不依赖任何人在任何时刻做出正确判断
后者更昂贵——它需要更复杂的基础设施,会限制一部分能力,需要更多的工程投入。但它也更可靠,因为它的有效性不会随时间衰减。
Anthropic 的结论,也是这篇文章的结论:安全系统最终应该建立在结构性约束上,而不是建立在对人类注意力的信任上。
这不是对用户的不信任,而是对系统设计者自己的诚实——我们知道人类的注意力是有限的,所以我们不应该让安全体系依赖它。
本文基于 Anthropic 工程师博客「How we contain Claude across products」(2026-05-25)。原文:https://www.anthropic.com/engineering/how-we-contain-claude
