三個代理,只偷一樣東西
在 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,給代理一個 — 連同一份憑 證 — 你輸得起的箱子。