三个代理,只偷一样东西
在 Black Hat USA 2026 上,Novee 用三种不同的方式攻破了 Claude Code、Gemini CLI 和 Codex 的默认配置,每条攻击链的起点都是一个匿名陌生人就能提交的 GitHub issue。三种绕过手法互不相关 — 引号解析不一致、未落实的 shell 允许列表、被信任的 AGENTS.md — 但三条链都终结于同一步:从代理自身的进程里读出真实凭证。Bromure Agentic Coding 不去加固这最后一步,而是把进程掏空:外泄照常执行,送出去的却是诱饵。
三家厂商、三个互不相关的 harness 漏洞、一个共同的最后动作:读出放在
代理进程里的 API 密钥或 token,再寄送出去。在 Bromure 的 profile 里,
那个值是一个 brm_… 占位符。外泄会成功,攻击者收到的却是一串在你的
Mac 之外毫无意义的字符串。
本周在 Black Hat USA 2026 上,Novee 发表了 “Trusted Enough to Run: Breaking AI Agents in Official Workflows”。研究 员 Elad Meged 以各厂商自家的公开仓库为对象,测试了三个编码代理的 默认配置,并且三个都攻破了。相关报道于 8 月 6 日 刊出。
三个案例的进入点完全相同,而且是成本最低的那一种:由零权限的匿名陌生人 开的 GitHub issue 或 pull request。代理在工作过程中读取这段不可信的文 本,而 harness — 围绕在模型周围、决定它能执行什么的那层代码 — 没能把这 段文本挡在界线的另一侧。Novee 在受测的三家厂商之外,还在 超过一百个公开仓库 上发现了同样脆弱的默认配置。
三条攻击路径彼此毫无关联。它们却终结在同一个地方,而这个共同的终点正是 值得带回家的部分。
三扇不同的门,同一面后墙
Claude Code
编号 CVE-2026-54316 的攻击链利用了两道接缝。第一道是 Claude Code 校验
命令的方式与 shell 实际解读命令的方式之间的错位:一段在校验器眼中无害
的引号字符串,到了 bash 手里却被解析成另一回事,一个
git push --receive-pack 标志就这样穿过了
二十三道安全检查
— 每一道就其本身而言都在正常工作。第二道接缝是外泄。一个只读的 tac —
把文件倒着打印出来的命令 — 就足以读出秘密,并倒序着经由 GitHub Actions
的日志送出去;另一个变体则靠反复触碰 HuggingFace 模型的公开下载计数器
再读回来,把 API 密钥一个字符一个字符地泄漏出去。Anthropic 已发布修复。
Gemini CLI
被评为 CVSS 10.0。在 headless 模式下,Gemini CLI 自动信任工作文件夹,
并加载在那里找到的任何代理配置 — 没有沙箱、没有批准 — 于是一个埋入配置
文件的 pull request,在沙箱还没初始化之前就已经执行。harness 的两个假设
同时失守:“受限”的 shell 允许列表在运行时从未被落实,而把秘密从子进程
清除的环境净化,却把它们留在父进程里,通过 /proc 即可读取。Google
在 0.39.1 和 0.40.0-preview.3 中对 headless 信任模型做出了破坏性
变更。
Codex
Codex 会在同一个共享工作区上跑两趟代理。.git 和 .codex 受写保护;
AGENTS.md 则不受,而且每次运行都会被当成可信指令重新加载。处理不可信
输入的第一趟写入一份被投毒的 AGENTS.md;“安全”的第二趟把它当成权威加
载,带着提升过的权限把恶意指令继续执行下去。OpenAI 在三天内把两趟拆成
相互隔离的作业。
相同的那部分
Novee 自己的总结是:“这些都不是简单的配置失误,而是正确的安全决策,在 交接点上崩解了。”就 harness 而言,这是正确的解读。但请看每条链终结在 哪里。
Claude 的 tac 读出凭证,HuggingFace 计数器泄漏的是 API 密钥。Gemini
的 /proc 缺口暴露的是父进程里的秘密。Codex 提权后的第二趟,把环境
里的 token 带进了攻击者控制的指令。三道互不相干的接缝以三种方式裂开,
而每一条的结尾都伸手去拿同一个东西:一个真实的秘密,就放在代理的进程或
环境里,等着被读走。
这正是所有这些漏洞利用共享的假设 — 只要能以代理的身份执行代码,凭证就
在手边。而它几乎总是在。ANTHROPIC_API_KEY、GITHUB_TOKEN、AWS 密
钥:运行编码代理的寻常方式,就是把它们全放进进程的环境变量里,因为工具
就是预期在那里找到它们。
Bromure Agentic Coding 不打算赢下 harness 的军备竞赛。它直接拿走 harness 所保护的东西。
链条在哪里断开
Bromure 让每个 profile 的代理跑在 Apple Silicon 上一台可抛弃的 Linux VM 里,并把它的每一个字节的网络流量都导经宿主机上的代理服务器, 位于代理所在的箱子之外。你可以运行 Novee 攻击 的同一种自主 issue 分流代理 — 由你自己托管,而不是交给工作流的 runner。 拿这三条链对照这个架构走一遍:每一条都会散开,而凭证那一步,三条链散开 的方式完全相同。
凭证从不在进程里
化解那共同最后一步的,正是这一项。Anthropic、OpenAI 和 xAI 的真密钥
以 brm_… 占位符的形式注入 VM,只在宿主机的代理服务器上、在线路
上、针对各自所属的唯一目的地主机,才换成真值。密钥从不在 VM 的内存
里,不在 /proc 里,不在任何子进程或父进程读得到的环境变量里,也不
在任何日志里。tac 读到的是诱饵。HuggingFace 计数器逐字符泄漏的是
诱饵。扫 /proc 捞回的还是诱饵。演讲里的每一种外泄都完整执行到
底,送出的字符串却只在唯一一台 Mac 上有意义 — 而那台 Mac 并不是它运
行的那台机器。
RCE 落在一个可以抹除的箱子里
“在运行代理的宿主机上执行代码”是 Gemini 公告里的措辞,而那台宿主机 正是 Bromure 挪动的信任边界。Gemini 抢在沙箱初始化之前的执行,和 Claude 的 shell 绕过,得到的都是一台可抛弃的 Linux VM:与 macOS 隔 着一层 hypervisor,位于 NAT 之后,你网络上的任何东西都碰不到。 Erase home 会丢弃该次运行写入的一切,把家目录重置回刚 clone 完 的状态。攻陷了代理的漏洞利用,攻陷的是一台你本来就打算扔掉的 VM。
写入 main 的动作在代理服务器被拒绝
两个提权瞄准的是同一份奖品:Claude 的链用 git push --receive-pack
推送,Gemini 的链把恶意代码推进主分支。这是供应链的那一半 — 被攻陷
的 checkout 在下游变成有毒的软件包。把 GitHub 护栏设成只读或阻止破
坏性操作,git-receive-pack 就会在宿主机的代理服务器被拒绝 — 在那
里,VM 里被绕过的守卫没有发言权。fetch 照常通过;会毒害分支的那次
push 则过不去。
指令文件在被服从之前先被评分
进入点是 harness 没能围堵的不可信 issue 和 PR 文本,而 Codex 的整条
链就活在一份被写入的 AGENTS.md 里。Bromure 用本地的提示注入检测模
型为代理读到的工具结果内容评分 — 网页、issue 正文、文件内容 — 并用
一个专用分类器加上隐形 Unicode 载荷扫描器,为权威文件本身
(CLAUDE.md、AGENTS.md 及其变体)评分。Codex 两趟之间那份被投毒
的 AGENTS.md,正是第二个检测器被打造来抓的东西,而且它在宿主机上
运行,赶在模型依据该文件行动之前。
这些设置里有两项默认开启,而凭证代理机制根本不是一项设置 — 它就是 Bromure profile 持有秘密的方式本身。隐蔽通道也被补上了:GitHub Actions 日志、HuggingFace 计数器、突兀的对外主机,全都得经过宿主机的代理服务 器,而 Security Log 和 Trace Inspector 会记录每个请求的主机、状态和替换 报告 — 那条泄漏了诱饵的侧信道,同时也是一张你读得到的清单上的一行。
harness 还会继续破
Novee 促成的三个修复都是好的,也都是窄的。Anthropic 修正了引号解析错 位;Google 改了 headless 信任模型;OpenAI 把两趟拆开。每一个都关上了被 找到的那道特定接缝。但没有一个改变三个漏洞利用的共同点:一份可用的凭证 就放在代理的进程里,任人取用。下一个 harness 漏洞 — Novee 在另外上百个 仓库上找到了同样的默认配置,所以一定会有下一个 — 还是会伸手去拿它。
你可以用补丁加上配置审查回应每一次披露,也应该这么做。但补丁关上的是一 个代理里的一扇门,审查则得一个仓库、一个版本地做。一个可用的漏洞利用伸 手去拿的那份凭证,在三个代理、在未来每一个漏洞里都是同一份,而它也是你 能靠一个决定就移出攻击范围的唯一东西:把真秘密留在宿主机上,交给代理一 个占位符,让代理服务器只对收件的那台主机产生真值。
安装 Bromure Agentic Coding,给代理一个 — 连同一份凭 证 — 你输得起的箱子。