大可的 AI Builder 手记
跟随系统
颜色主题
长沙小桌实战
大可 Dako
大可 Dako大可 DakoAI Builder · Agent 实践者用 AI 做真正能用的产品。专注探索 Agent 工程化落地、Vibe Coding 实践与商业化交付。
内容平台即将上线,敬请期待
模型层只能降低概率,兜底在环境层沙箱边界限定文件系统与网络出口凭证最小权限按 Tool 和资源下发数据边界外部内容一律只是数据分级审批只拦高风险动作审计与身份AI-BOM 与可验证委托链能做什么由沙箱定,何时授权由审批定
沙箱决定技术上能做什么,审批决定什么时候需要授权。

沙箱、凭证与人机边界

模型层防御永远到不了 100%,唯一可靠的兜底是环境层:文件系统边界、网络出口、按 Tool 最小权限的凭证,以及外部内容一律是数据。

模型层防御永远到不了 100%:Anthropic 在 Gray Swan 红队基准上测得 Opus 4.7 单次攻击成功率约 0.1%,自适应攻击一百次后升到 5–6%,auto mode 对真实过度积极行为的漏报率仍有 17%。兜底在环境层——文件系统边界、网络出口、按 Tool 最小权限的凭证,以及一条硬规则:外部内容一律是数据。

兜底在环境层

内部红队做过一次钓鱼:恶意 prompt 伪装成常规任务,其中一步让 Claude 读 ~/.aws/credentials 后编码 POST 到外部 endpoint。25 次重试,24 次成功外泄。这是直接 prompt injection——攻击指令经由用户本人到达,模型层防御锚定在「用户意图」上,用户正在打字,分类器无异常可抓 anthropic-contain。

唯一靠谱的防御在环境层:egress 控制不管意图一律阻断 POST,文件系统边界让 ~/.aws 不可达。

但 allowlist 也会被打穿:一起真实事件里,恶意文件携带攻击者自己的 API key,把数据编码发往 api.anthropic.com,域名在白名单上,请求「完全合法」。allowlist 只管「去哪儿」,不管「谁在发、代表谁」。解法是在 VM 内部署 MITM 代理,只转发携带本会话 token 的请求——控制点移到身份。

三层护栏,按被绕过的难度排

书里把护栏分成三层:上下文层管「模型能看到什么」,执行层管「模型能做什么」,数据层管「世界最终能被改成什么样」。这三层不是按请求处理的先后排,而是按被绕过的难度排——越靠下越不依赖模型自己的判断,因此越难被一次成功的注入穿透 ai-agent-book。

上下文层只能降低概率,给不出保证,原因是结构性的:处在同一个上下文里的 Agent,很难判断自己是否已经被注入。这一层的工业上限也就是把便宜的手段放在前面——Anthropic 的 Constitutional Classifiers 用自然语言规则生成合成数据来训练输入/输出分类器,并把提问与回答放在一起联合判断(有些回答单独看毫无问题,对照提问才看得出是暗语),再用两级筛查:一个几乎零成本的探针直接读模型内部激活扫全部对话,可疑才交给更强的分类器复审,于是第一级误报多也不影响体验 ai-agent-book。

执行层要成立,复核必须在上下文之外完成:独立审查进程、最小权限凭证、沙盒隔离、人在回路。否则它会和被注入的那个 Agent 一起沦陷——这跟让嫌疑犯自查有没有作案是同一件事。数据层是最后一格,也是唯一不依赖上面两层是否正确的格:把「谁能对哪条数据做什么」交给行级安全策略、约束与校验器、受控视图与存储过程,以及由受信任运行时绑定、无法伪造的访问上下文。即使提示注入得手、生成的代码完全漏写权限判断,越权操作仍然会在数据层被拒 ai-agent-book。

护栏还有另一类失败:误拒绝。为了压低危险请求被放行的概率,模型会连带拒绝一部分合法但形式敏感的任务,例如经过授权的安全测试。所以护栏的评估必须双向做——只测「该拦的拦住没有」,等于没测「明确允许的能不能正常完成」。

沙箱定能力,审批定时机

沙箱决定技术上能做什么,审批决定什么时候需要授权。两者都要有,顺序不能反:先用沙箱收窄可达面,再决定哪些残留风险需要人点头。反过来,就是次次弹窗而用户几乎全都同意。

审批请求要能验证:id、runId、actionType、toolName、riskLevel、exactEffect、affectedResources、proposedInput、expiresAt、version 缺一不可;等待期间任务要版本化,恢复前重跑 Guardrail。「点过一次同意」不是无限期授权。

还有信任边界建立之前的执行:开发者 clone 仓库 review PR,.claude/settings.json 里的 hook 在「Do you trust this folder?」弹出之前就被解析执行了。三个同类漏洞的修法一致——把项目本地配置的解析推迟到用户接受信任之后 anthropic-contain。

脑、手、会话三分

Brain(模型、runtime、上下文引擎、planner)可无状态伸缩;Hands(工具执行器、浏览器、Shell、文件系统、外部 API、凭证)单独沙箱限权;Session(事件、checkpoint、历史、审批、产物)是可恢复事实源。

分开的理由只有一条:凭证可达即风险。不可信代码与凭证同容器时,一次 injection 只要说服它读自己的环境就够了。窄 scope 能缓解,却编码了「模型用有限 token 做不了什么」的假设——模型越聪明,假设越先失效。修法是让 token 永远不可达:凭证捆绑资源(初始化时写进 git remote),或存于 sandbox 外的 vault 由 proxy 代调。

再配一条数据规则:网页、邮件、PDF/Office、Tool 输出、检索片段、MCP 资源、外部 Agent 消息、用户上传代码,全部是数据。审计过的连接器不等于审计过的数据——过了 malware 检查的 GitHub 连接器照样载入 poisoned README。高风险 Tool 前检查参数是否来自这些来源。

从被动防御到完整容器生命周期

很多团队把沙箱理解为一个被动的安全外壳,或者简单的 Linux 命令黑名单(例如禁止执行包含删除字符的命令)。但是这种字符串黑名单极易被系统别名或编码转换轻易绕过。

在现代云原生架构下,沙箱的安全属性必须升华为一套完整的运行环境生命周期管理体系:

生命周期阶段 核心工程机制 安全与业务保障
动态初始化 基于不可变基础镜像秒级分配独立轻量容器 每个任务拥有全新隔离环境,彻底杜绝多租户交叉污染
执行隔离 只读系统盘 + 临时写时复制(CoW)层 任务内部的破坏性写入局限在临时层,基础环境永远不可变
网络边界 默认完全断网,出口经受控反向代理网关过滤 阻止模型受诱导外传代码,防止恶意脚本向外部回传数据
凭证代调 真实密钥驻留于沙箱外部,沙箱内仅持有临时短期代币 即使沙箱内部被彻底攻破,攻击者也拿不到长期有效的系统凭证
终态销毁 交付物经由收据归档后,整个容器实例彻底物理擦除 临时缓存与内存数据即时清空,无任何后门残留的可能

这种将防御嵌入生命周期的做法,在 面向过程的 Agent 运行时 中构成了执行宿主的基础。它把原本被动的安全审核,转变为不可变基础设施与一次性销毁的物理确定性。

但「终态销毁」这一格有个前提常被默认成立:块在交给下一个租户之前已经清零。Cloudflare 2026 年 9 月披露的跨租户泄露证明这个前提会失守——漏洞不在虚拟机边界上,而在边界之下的存储分配器。容器根盘用精简配置(dm-thin)分配,受影响资源池的块大小为 64 KiB 并启用了「分配时不清零」选项;写入单个 4 KiB 块时,系统分配一个 64 KiB 物理块,写入只覆盖 4 KiB,剩余最多 60 KiB 保留着上一个容器的内容,原始读取磁盘就能拿到新容器从未写过的字节。研究者在六个生产部署中测了 5614 个目录块,全部来自其他用户,并恢复出目录结构、数据库页与结构完整的 SQLite 数据库 cloudflare-tenant。

修复也不止于改一个开关。移除该选项只恢复新分配块的默认行为,已映射到现有块设备里的块(包括运行中容器磁盘与主机为镜像层准备的快照缓存)不会被清理,新容器可能继承这些映射——所以还要停用运行中磁盘、清空主机数据、重启虚拟机、清空镜像缓存。

判据是:隔离要逐层验证,而不是在架构图上宣布。 虚拟机边界成立,不代表其下的存储分配器、卷复用、快照缓存也成立。共享存储上的残留数据应视为首要隔离控制项,「分配时清零」或「释放时擦除」必须显式配置并单独测过,不能依赖默认值。

记忆投毒不是 prompt injection

攻击者在一次会话往长期记忆写入恶意内容,在未来的无关会话触发支付、改配置、外传。它持久生效,触发时攻击者无需在场。

内容检测和信任打分防不住:八个前沿模型的基准上最高 68% 攻击成功率;Gemini-Flash 的信任打分给 54 条投毒条目全打 1.0,防御退化成置信度过滤器而非安全过滤器。投毒内容在激活前表现良性,写入时查不出异常;还有三条洗白通道:agent 自我总结改写、可信工具回显、伪造共识 arxiv-memory-poisoning。

能做的是三件事:写入时绑定不可变来源标签(转述自不可信来源的笔记继承不可信标签);敏感动作前做 act-gate,确定性检查来源链,不可信记忆不得触发支付、外传、配置变更,一次约 1.3 微秒,比 LLM judge 便宜六个数量级;权限提升需独立可信方背书。

审批疲劳、AI-BOM 与委托链

遥测显示用户批准约 93% 的提示,批得越多越不专心。auto mode 两层防御(输入层 injection probe、输出层 transcript 分类器)之后,真实过度积极行为的漏报率仍有 17%;多数漏判不是没识别危险,而是误判「会话里的同意信号是否覆盖这个动作」——「clean up the PR」没有授权 force-push anthropic-auto-mode。

所以审批要分级:难撤销、跨边界、动钱动权限的才拦人,其余交给沙箱和能力 allowlist。目标不是人看过每一条,而是人只在判断力有增量时出现。

比逐动作审批更进一步的形态是计划即权限:Agent 先在只读范围内自动调查问题,然后提交一份计划——写明要做什么、需要哪些权限——用户一次审批整份计划,批准才授予超出只读基线的权限。计划里显式连着四个环节:意图、工作项、所需权限、强制执行点。两条边界要守住:批准授予的权限不能超过用户自己已有的权限,Agent 是代行而不是扩权;只读操作也可能泄露敏感信息,自动放行不等于无害 vercel-plan-permissions。反面形态就是逐动作弹窗——用户还不知道 Agent 打算怎么解决时就被迫逐项批准,反复弹窗把审查变成惯性点通过。

身份还有一个容易被漏掉的拆法:按动作拆,不按人拆。同一个群里不同人会让 Agent 读文档、提交代码、执行部署、查受控资源,如果全用一套身份,要么权限不足要么被无意放大。原则是「谁消费数据用谁的权限,谁产生结果记谁的归属」——读文档用当轮发送人身份,平台动作(构建部署)用服务身份,提交代码用发送人署名,查受控资源走负责人本人登录确认的显式委托。最要紧的一条是模型不能指定任意身份:身份化调用只接受受控角色(当轮发送人、服务身份、已确认负责人),角色到真实身份的映射由可信环境注入,模型生成「以某某身份查询」时控制层直接拒绝(天猫数字员工的生产实践)。

剩下两件在资产层。AI-BOM:模型、工具、MCP 端点、数据集都是供应链风险面,不可见则不可管,上线前生成清单并纳入 CI 增量扫描。非人类身份:每个 Agent 有唯一身份并关联人类责任主体,能回答「代表谁、被谁授权」,跨 Agent 委托保留可验证链条、权限逐级衰减,这正是那起 egress 事件的补法。

代价是工程投入和一部分自主性,纯只读无凭证的助手不需要全套。检查方法:挑最危险的 Tool,问「模型此刻被完全接管能造成多大损失」——答案是你的沙箱边界,不是审批弹窗。

参考资料

  1. How we contain Claude across products
  2. How we built Claude Code auto mode
  3. Securing LLM-Agent Long-Term Memory Against Poisoning
  4. 《AI Agents in Depth》第一章 AI Agent 入门
  5. InfoQ 编译:Cloudflare 修复了容器中的跨租户数据泄露问题
  6. How Vercel Agent accesses production safely(Vercel)