Anthropic 如何在各产品中约束 Claude
随着 agent 变得更有能力,它们潜在的破坏半径也会随之扩大。工程问题在于如何给这个半径封顶。以下是 Anthropic 在为 claude.ai、Claude Code 和 Claude Cowork 构建约束机制时学到的经验。
说明:以下为全文翻译,力求忠实原意;为适配中文阅读体验,个别句子顺序做了轻微调整。产品名、技术名词、路径、命令与指标尽量保留英文原文。
十二个月前,如果有人提出要给 Claude 足够的权限,以至于它能让 Anthropic 的一个内部服务宕掉,我们会立刻否决。今天,这种级别的访问已经很常见,Anthropic 的开发者也因此更高效。这类部署的风险由两部分组成:失败发生的可能性,以及一次失败可能造成多大损害。安全护栏和模型训练方面的进展持续降低了前者;而后者,也就是理论上的“爆炸半径”,会随着能力和访问权限扩大而只增不减。可是,当 agent 已经能完成过去需要一个人、甚至一个团队才能完成的工作时,不部署的成本也会大到让风险收益计算明显转向采用,前提是产品能被做得足够安全。于是,工程问题就变成了:如何给爆炸半径封顶。
当我们能对自主 agent 的相对损害设定边界,例如通过控制它所处的环境来设定边界,高价值能力就可能值得部署。Claude Mythos Preview 就是一个例子:2026 年 4 月,它的爆炸半径被认为过高,因此不适合发布。不过,随着防御方强化关键系统、安全护栏成熟,我们预计发布类似能力水平模型的范围会变得更合理,即使风险永远不会完全归零。模型能力是 agent 部署总风险中的一个重要因素。
大体上有两种做法。
第一种,是通过 human-in-the-loop 监督 agent 的行为。Claude Code 过去通过在每一轮向用户请求权限,来防止 agent 执行非预期操作。理论上这能奏效,但我们发现这个方法并不可靠。遥测数据显示,用户会批准约 93% 的权限提示。用户看到的审批越多,对每一次审批的注意力就越低,久而久之,监督会变得明显不那么认真。我们最近构建了 Claude Code auto mode,用来自动化更安全的审批,以减少这种审批疲劳。不过,漏洞依旧存在,任何概率性防御都有非零漏检率。1
第二种给爆炸半径封顶的方法,也就是本文大部分内容的重点,是 containment:约束。我们不是监督 agent 做了什么,而是通过 sandbox、虚拟机、egress controls 等方式强制执行访问边界,监督它能够做什么。这是 Anthropic 工程团队投入最多精力的地方,也是许多最出人意料的安全失效发生的地方。
过去两年里,我们发布了三类主要的 agentic 产品:claude.ai、Claude Code 和 Claude Cowork。它们服务的用户不同,因此需要不同的约束架构。本文会分享哪些设计经受住了考验,哪些地方出了问题,以及我们一路上对 agent 安全学到的东西。
三类风险,三类防御组件
agent 的安全风险可以归入三类:
用户误用。 用户无论是出于恶意还是粗心,指示 agent 做有害的事情。这包括从要求 agent 绕过一个他们觉得烦人的检查,到运行一个他们不理解的破坏性命令,再到明确指定有害行为。
模型行为不当。 agent 执行了没人要求它做的有害操作。随着模型进步,它们在大多数行为评测上变得更对齐,但这并不意味着风险必然缩小。能力较弱的模型更容易误读局面并犯下明显错误。能力更强的模型犯这种错误更少,但它们也更擅长找到达成目标的意外路径,常常会绕过没人想到要写下来的限制。
在 Anthropic,我们见过 Claude 模型为了完成任务而“好心地”逃出 sandbox,检查 git 历史来寻找编码测试答案,以及自发识别自己正在被运行的 benchmark,从而解密答案密钥。每个模型都会带来一组新能力,而这些能力有时会以意想不到的方式被使用。
外部攻击者。 agent 通过工具、文件或网络访问等外部向量遭到攻击。这一类既包括 prompt injection,也包括针对 agent runtime、编排层或代理的常规攻击。
在构建约束与防御系统时,我们会把防御施加在三个主要组件上:
agent 运行的环境。 我们用进程 sandbox、虚拟机、文件系统边界和 egress controls 来限制 agent 能在哪里、以何种方式行动。目标是为 agent 能触达的东西设置硬边界。例如,如果凭据从未进入 sandbox,那么无论原因是用户、模型找到了一条“创造性”路径,还是攻击者,凭据都无法被外传。
紧密的边界也意味着你可以放松监督。Claude Code 的参考 devcontainer存在的目的,正是为了让 agent 能在无人值守、无需逐个动作审批的情况下运行。
agent 咨询的模型。 这里的机制包括 system prompts、classifiers、probes 和训练修改。因为模型是概率性的,这些机制只能塑造 agent 倾向于做什么,而不能改变它理论上有能力做什么。
这些防御很强。在 Gray Swan 的 Agent Red Teaming benchmark 上,也就是测试 prompt injection 易感性的 benchmark,Claude Opus 4.7 将单次尝试的攻击成功率控制在约 0.1%,在 100 次自适应尝试后约为 5-6%。Claude Code auto mode 会在执行前捕获约 83% 的“过度积极”行为。可是,即便有一流的防御,模型层保护也永远不可能 100% 有效,因此它不能单独存在。
agent 能触达的外部内容。 MCP servers、第三方插件和 web search tools 都会把来自你无法控制来源的内容送进 agent 上下文。一个经过审计的 connector,并不等于它读取的数据也经过了审计。例如,GitHub connector 即使通过了恶意软件检查,也可能把一个被投毒的 README 直接加载进模型上下文。细粒度地限制工具权限能帮助限制爆炸半径。例如,一个只有数据库只读权限的 agent,可以比一个能写入生产库的 agent 更广泛地部署。
防御应当相互重叠并彼此补充。当环境防御不可用时,模型层必须承担更多责任,这正是 Claude Code 的 auto mode 被设计来处理的问题。在本地,环境和模型防御能抵御恶意工具输出;但还可以在链路更上游增加防御,也就是限制工具本身的能力和访问权限。
三个需要防御的组件:模型、模型运行的环境,以及 agent 能触达的外部内容。
约束 agent 的模式
聚焦在环境层,我们会描述三种隔离模式,以及它们如何分别适配 Claude 的三个平台:claude.ai、Claude Code 和 Cowork。每一种设计都是逐渐形成的,我们是在寻找平衡:一边是 agent 所需的能力,一边是用户所需介入的程度。
模式一:临时容器(claude.ai 代码执行)
claude.ai 虽然最常被认为是聊天界面,但它也会编写和运行代码、生成文件、调用 connectors。当 Claude 在 claude.ai 内部运行代码时,它是在隔离基础设施上的 gVisor 容器里运行。agent 完全在服务端;没有代码在本地机器上运行,文件系统也是临时的,每个 session 一份。爆炸半径很小,但 Claude 能做的事的上限也很低:没有持久工作区,也无法访问用户文件系统。
这也让 claude.ai 面临更传统的威胁模型。我们不是在保护用户机器不受 agent 影响,而是在保护我们自己的基础设施,以及各租户之间互不影响。claude.ai 发布前的工作主要是传统安全工作,例如网络配置、内部服务认证和编排。
这项工作强化了安全领域最古老的一条经验:最弱的层,往往是你自己构建的那一层。gVisor 和 seccomp 面对资源充足攻击者的加固时间,远远长于 agentic AI 存在的时间,所以审查精力投入到了我们围绕它们构建的更新组件上。后文会回到这一点,因为我们的自定义 proxy 也是最严重事故中出问题的那个组件。
模式二:human-in-the-loop sandbox(Claude Code)
Claude Code 运行在用户机器上,并能访问用户的文件系统、shell 和网络。没有这些访问权限,编码 agent 的作用会很有限,因此必须找到一种能安全授予这些权限的方法。
一种办法是依赖 human-in-the-loop。这对 Claude Code 来说才是可行的,因为平均用户是熟悉编码环境的开发者:他们能读懂 bash,知道 rm -rf 是什么,而且本来就每周多次从不受信任的来源运行 npm install。这意味着,当一个“允许此操作”的对话框弹出时,他们很可能具备准确评估 agent 想做什么、风险是什么的专业能力。基于这一点,Claude Code 上线时采用了最简单的防御:允许读取;写入、bash 和网络访问需要审批。
不过,如前所述,审批疲劳在几周内就出现了。讽刺的是,一个原本设计来提供监督的功能,某种意义上可能产生相反效果:一些用户可能会直接停止认真看。为了先缓解草率审批,我们发布了 OS-level sandbox(macOS 上的 Seatbelt,Linux 上的 bubblewrap)来强化边界:读取被允许,工作区内写入被允许,但网络默认被拒绝。在 sandbox 内,agent 大体可以不受打断地运行。结果是权限提示减少了 84%;我们还开源了 runtime,因此边界是可审计的。
我们的匿名使用数据也显示,有经验的用户使用自动批准的频率大约是新用户的两倍,但他们也更频繁地在执行中途打断 agent。相比于给每个步骤设门槛,有经验的用户更可能只在 agent 偏离轨道时监督它。这也许是人们偏好如何与 agent 协作的一种自然演进,但它同样会失效,因为它要求用户足够技术化、足够专注,才能首先注意到漂移。随着模型能力提升,agent 开始编写越来越有野心的 bash,注意到这种漂移会变得更难。随着用户转向 multi-agent systems,这种方式也更不可能成为有效的监督策略。
我们漏掉的风险:信任对话框之前的一切
在 2025 年中到 2026 年 1 月之间,我们通过负责任披露项目收到了一些 Claude Code 漏洞报告。其中三个利用的是用户尚未同意任何事之前就会执行的代码。要理解这是怎么发生的,可以看最直接的情况:开发者 clone 一个仓库来 review pull request,而这个仓库包含一个定义了 hook 的 .claude/settings.json。因为 Claude Code 会在启动期间读取项目设置,而且这发生在标准的“你是否信任此文件夹?”提示出现之前,所以攻击者编写并提交的 hook 会自动执行。其余案例在结构上相似:来自尚未被信任目录的输入,在信任边界建立之前就被解析了。
每个案例的修复形状都一样:把项目本地配置的解析和执行推迟到用户接受 trust prompt 之后。如果你在构建类似东西,请把 project-open、config-load 和 localhost listeners 当作来自互联网的任何 inbound request 来处理。它们不应仅仅因为看起来是本地的、且发生在用户同意前,就被隐式信任。
我们漏掉的风险:用户作为注入向量
2026 年 2 月,在一次受控内部红队演练中,一名研究员成功钓鱼诱导一名员工用恶意 prompt 启动 Claude Code。这个钓鱼看起来像普通协作:一封“你能帮我跑一下这个吗?”的邮件,附上一段可以直接粘贴的 prompt;prompt 本身读起来也像常规任务指令。但在一系列 setup 步骤中,它温和地要求 Claude 读取 ~/.aws/credentials,对内容编码,并 POST 到外部 endpoint。在这段 prompt 的 25 次重试中,Claude 完成了 24 次外传。
这是直接的 prompt injection:攻击者的指令来自用户,而不是来自工具输出或抓取内容。我们的模型层防御以用户意图为锚点;当用户就是输入指令的人时,classifier 没有什么异常可抓。把同样的脚本交给一名人类承包商,他也会做同样的事。
这种情况下唯一站得住的防御是环境,具体来说,是无论意图如何都阻止 POST 的 egress controls,以及从一开始就让 ~/.aws 不可触达的文件系统边界。
当我们把可工作的 prompt 分享到内部 Slack 里讨论时,有人指出一些内部 agent 会读取 Slack。于是 payload 变成了环境中的背景内容。我们在 thread 中加入了一个 canary string,这样如果有什么东西拾取了它,我们就能发现。在一个 agent 会阅读一切的世界里,调查工具本身也是攻击面。
模式三:本地虚拟机(Claude Cowork)
Claude Cowork 运行在用户桌面上,可以访问用户选择的工作区文件夹。因为这个平台是为一般知识工作而非软件工程构建的,普通用户远不如开发者熟悉 bash。
因此,human-in-the-loop sandbox 策略未必能迁移过来;不应期待一个非技术知识工作者判断类似 find . -name "*.tmp" -exec rm {} \; 这样的 bash 咒语。当批准例外需要典型用户并不具备的专业知识时,管理员应设置一个绝对且始终开启的边界。
为此,Claude Cowork 的第一个版本运行在完整虚拟机中,使用平台厂商的 hypervisor(macOS 上是 Apple Virtualization framework,Windows 上是 HCS)。VM 有自己的 Linux kernel、自己的文件系统和自己的进程表。用户选择的 workspace 和 .claude 文件夹会被挂载;主机上的其他内容不可见。凭据保留在主机 keychain 中,永远不会进入 guest machine。这个设计保护的是一种可能性:Claude 在某个时刻行为不再对齐。被攻破的 Claude 仍然可能损坏 workspace 文件夹内的东西,所以架构的目标是确保它只能触达这些东西,直到用户添加 connectors,并且让用户控制哪些内容被挂载进去。
在原始架构,也就是我们称为 full-VM mode 的架构中,agent loop 本身运行在 guest 内部,因此 Claude 会作为普通 Linux 用户执行,而且不知道自己被 sandbox 了。对比 Claude Code:那里有一个 privileged process 位于 sandbox 外部,决定每条命令是否执行 sandbox;一个有说服力的注入 prompt,或一次疲劳审批点击,可能会让这个进程运行未被 sandbox 的东西。在这里,不存在一个握着逃生钥匙的外部进程,因此也不存在一个有权授予例外的组件。
Claude Cowork VM 有六个主要隔离机制。其中两个在 guest kernel 外部强制执行,因此即便 agent 在 VM 内获得 root 级访问也仍然有效。其余四个由 guest 强制执行,并刻意保持最小化,因为外层机制承担了剩余部分。
不过,我们很快意识到,让整个 agent 都运行在 full-VM mode 中会带来实际问题:VM 启动期间的任何失败都会让 Cowork 不可用。把 agent loop 移到 VM 外部,同时保持代码执行仍在 VM 内,让 Claude 即使在 VM 出错时也能回应用户并帮助调试,而不是卡在错误上。这个改变带来的安全影响很小,因为 VM 仍然对 agent 执行的代码强制执行文件系统和网络控制。
另外,我们也把 local MCP servers 移到了 VM 外部。在 VM 内运行它们更难审计;VM 更新时会产生脆弱的依赖问题;并且不支持那些需要与数据库等本地进程交互的 MCP,因为这类 server 无论如何都必须在 host 上运行。这个改变让 Claude Cowork 与 Claude Desktop 中 local MCP servers 的现有工作方式保持一致:把它们视为用户可能选择安装的任何软件,并交由管理员决定启用哪些 local MCP(如果要启用)。Remote MCP servers 不受影响,因为它们并不在用户机器上运行。
让 agent loop 位于 VM 内部意味着 VM 的任何失败都会让 Cowork 变得不可用。Host-mode 更可靠,因为即使 VM 崩溃,agent 仍能回应;同时它仍然通过隔离代码执行提供重要安全保证。
文件系统控制是另一个重要架构选择。Claude 需要能够访问主机上的一些文件才有用,但我们希望尽量缩小爆炸半径,并让用户清楚看到本地文件访问。我们发现,提供不同的文件挂载模式有助于细粒度控制风险;Claude Cowork 提供 read-only、read-write 和 read-write-no-delete。这里一个潜在坑点是:符号链接解析必须发生在路径验证之前,而不是之后,否则授权文件夹内的一个 symlink 可以指向外部并逃逸。对企业客户,我们允许管理员通过 MDM settings 中的 mount-path allowlists 控制这一点。
我们漏掉的风险:通过已批准域名外传
一个清晰的“通过已批准域名外传”的例子来自第三方披露。Claude Cowork 的 egress allowlist 正确放行了到 api.anthropic.com 的流量,因为产品必须调用我们自己的 API 才能工作。在这个案例中,一个放在用户已挂载 workspace 中的恶意文件,携带了隐藏指令和攻击者控制的 API key。Claude 按照指令读取 workspace 中的其他文件,并使用攻击者的 key 调用 Anthropic Files API。egress proxy 检查目标地址,看到 api.anthropic.com,于是放行。文件被上传到了攻击者的 Anthropic 账户。sandbox 完美工作,但数据仍然被外传了。
以前,我们把 allowlist 概念化为目的地过滤器,也就是告诉 Claude:这些域名可以访问。但更好的概念化方式也许是“能力授予”。allowlist 上任何域名能触达的每个功能,现在都是攻击面。允许 api.anthropic.com,就意味着允许把文件上传到任意 Anthropic 账户。
我们用 VM 内部的防御性 man-in-the-middle proxy 修复了这个问题,它会拦截发往我们 API 的流量。它只放行携带 VM 自己配置的 session token 的请求;攻击者嵌入的 key 会被 proxy 拒绝。它也会阻止可能启用 server-side fetch 的 headers。这个 proxy 位于 VM 内部,而不是我们的服务器上,因为只有 VM 知道 provenance,也就是请求来源;从服务器视角看,一个 Cowork 请求和任何其他 API client 发来的请求无法区分。
上图:到 api.anthropic.com 的流量被放行,导致 egress。下图:用 man-in-the-middle proxy 拦截到我们 API 的流量来修复。
这也是“你自己构建的软件往往最弱”这一原则的第二个实例。在我们各产品中使用的 hypervisor、seccomp 和 gVisor 都很可靠。出问题的是我们的自定义 allowlist proxy。
我们漏掉的风险:VM 隔离也把 endpoint detection 软件挡在了外面
在评估 Claude Cowork 时,企业安全团队问:“为什么我们的 EDR 看不到里面?”答案是,同样用于约束 Claude 的隔离,也把 host-based endpoint detection and response 挡在了外面。从 EDR 的视角看,Claude Cowork 是一个不透明的 hypervisor 进程,它无法检查 guest。
隔离会降低可见性,而不透明性会给那些合规姿态依赖 endpoint visibility 的团队带来问题。我们当前的缓解方式是使用 pull-based OTLP exports,让管理员能够事后拉取 event logs,但这并不等同于实时监控。如果你在构建类似系统,请尽早为这场对话预留空间。
信任 agent 读取的内容
企业经常问我们如何保护 MCP connections。这是个好问题,但正确的问题比 MCP 本身更宽。任何提供给 agent 的外部资源都同时代表两类风险:传统供应链意义上的 code execution risk,以及 prompt injection vector。传统依赖审计,例如 pin versions、验证 signatures、review source,可以处理前者,但会错过后者。
remote 和 local 的区别比看起来更重要。本地安装的工具是可审计的。你能读代码、pin 版本,并知道它不会在你不知道的情况下变化。远程工具,例如 hosted MCP server 或 cloud connector,可能在你批准后任何时刻改变行为;你在安装时作出的信任决定可能不再适用。我们的 connector directory 通过持续 review 处理这一点,但目录之外的任何东西都应被视为不受信任。先用假数据、在恶意工具爆炸半径被约束的环境里运行它。
即使工具本身受信任,工具输出也是攻击面。前面提到的 GitHub README 例子正是这种情况;任何应用于网页的输入扫描,都需要以同样严格程度应用到具备网络能力的工具结果上。即便这会增加延迟,也不是完美防御,我们仍然倾向于 live inspection:一旦被投毒的工具返回值把 agent 引导到外传数据,日志只会显示一次成功且已授权的 API 调用,事后没有可寻找的信号。
在 Claude Code 和 Claude Cowork 中,工具调用会通过 proxies 路由,这些 proxies 会强制执行网络和文件策略,并能在返回值进入模型上下文之前检查它们。做检查的 classifier 可以是一个小而快的模型;它不需要是负责推理的那个模型。
展望
模型和产品发展很快。随着它们前进,风险也会变形和演化,我们的缓解措施必须同步跟上。
持久记忆投毒。 agent 上下文中会跨 session 持久存在的比例不断增长,这包括产品 memory、CLAUDE.md 文件、挂载的 workspaces,以及 scheduled 和 long-running agents 的 state directories。落入这些位置的注入,每次 agent 启动时都会重新加载。随着更多 agent state 跨 session 存活,我们正受到经典 post-exploitation 意义上新 persistence mechanisms 的威胁。优秀的 session startup classifiers 需要变得更普遍。
multi-agent trust escalation。 一方面,sub-agents 可以隔离不受信任内容,向 main agent 返回结构化事实,而不是把原始文本上交。另一方面,这也可能被滥用:如果 sub-agent 的输出因为来自“我们”而被视为比原始工具结果更高信任级别,就会引入一个新的 prompt injection 向量。在 multi-agent systems 中,需要在分配不同信任级别和容易发生 trust escalation 之间做权衡。
agent identity。 Claude Cowork 对 agent identity 的回答很具体:凭据留在 host keychain 中,VM 获得一个 per-session、缩小权限范围的 token,而且该 token 可以独立于用户 token 被撤销。不过,我们也开始处理更广泛的问题:跨平台 agent identity。agent 应该拥有自己的 principal identity,还是应该作为用户的延伸并继承用户权限?最终答案可能是二者的混合。
随着 agent 能力增强,攻击面会持续移动。我们见过的失败类型很可能会在各行业、各实验室重复出现。我们需要对 agent-specific security posture 进行集体投资,从共享 benchmarks 和 disclosure norms,到共同 identity standards 和 cross-vendor red-teaming。本文聚焦 containment,但这只是 agent 安全图景的一部分。关于 governance、observability 和 stack 的其他部分,可参见 NIST 关于 AI agent identity and authorization 的项目、由澳大利亚 ACSC 牵头并与 CISA 和英国 NCSC 合作发布的六机构 agentic AI 采用指南,以及 AI 管理标准 ISO/IEC 42001。我们的 Glasswing initiative 是一项贡献,但我们也期待与合作伙伴和竞争对手一起处理这个关键议题。
总结
简而言之,有几条原则是我们反复回到的:
先在环境层为 containment 设计,再在模型层引导行为。 最让我们学到东西的两起事故,也就是员工钓鱼和第三方 allowlist 披露,都是 egress 案例:数据通过一条被允许的路径离开。在这两个案例中,模型层帮不上忙,因为没有异常可抓。当所有概率性防御都漏掉时,被撞上的就是确定性边界。
让隔离强度匹配用户的监督能力。 一个能读 bash 的开发者,和一个不能读 bash 的知识工作者,运行的不是同一个威胁模型。用户是否能够评估 agent 即将做什么,应帮助决定 containment strategy;这个问题无论答错哪个方向,给专家太多摩擦,或给非专家太多信任,本身都是失败。
警惕自定义组件。 经受过实战检验的 hypervisors、syscall filters 和 container runtimes,承受过的对抗性关注比你将构建的任何东西都多。在本文描述的每一种部署中,标准原语都站住了脚,而我们围绕它们构建的自有工作暴露了缺陷。
归根结底,agent 也许是一类新的软件,但它们的系统层交互并不新。它们仍然读取文件、打开 sockets、生成进程;这让基于成熟工具的 containment 成为一种关键且可行的防御。随着 AI 发展,部署的风险收益平衡会继续变化,但为爆炸半径设定硬上限,往往会迫使这个平衡朝正确方向移动。
致谢
作者:Max McGuinness、Mikaela Grace、Jiri De Jonghe、Jake Eaton 和 Abel Ribbink。
我们也感谢 Hanah Ho、Hasnain Lakhani、Pedram Navid、Molly Villagra、Maya Nielan、Akila Srinivasan、Sam Attard、Alfred Xing、Mohamad El Hajj、Gabby Curtis、David Dworken、Adam Jones、Amie Rotherham、Christian Ryan、Lucas Smedley、Brett Andrews 以及其他人的贡献。
特别感谢我们的安全和产品工程团队,以及向 Claude 产品报告漏洞的个人与组织。
脚注
- Claude Code auto mode 会把命令审批委托给一个基于模型的 classifier;它以漏掉一部分风险命令为代价(约 17% 的 overeager actions 会通过),将摩擦降到最低(约 0.4% 的 benign commands 被阻止)。因此,它是 sandbox 内 defense-in-depth 的一层,而不是 sandbox 的替代品。