返回所有文章
發佈於 · 作者 Renaud Deraison

三個代理,只偷一樣東西

在 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.10.40.0-preview.3 中對 headless 信任模型做出了破壞性 變更。

Codex

Codex 會在同一個共享工作區上跑兩趟代理。.git.codex 受寫入保護; AGENTS.md 則否,而且每次執行都會被當成可信指示重新載入。處理不可信輸 入的第一趟寫入一份被下毒的 AGENTS.md;「安全」的第二趟把它當成權威載 入,帶著提升過的權限把惡意指示往下執行。OpenAI 在三天內把兩趟拆成互相 隔離的工作。

門各不相同,後牆卻是同一面Claude Code · CVE-2026-54316驗證器與 shell 對同一字串解析結果不同--receive-pack 通過 23 道檢查tac 讀取;Actions 日誌帶出HF 計數器逐字元洩漏Gemini CLI · CVSS 10.0headless 模式自動信任資料夾設定在沙箱啟動前就執行「受限」允許清單從未落實子行程已清空,父行程的祕密仍可經 /proc 讀取Codex · AGENTS.md兩趟共用一個工作區.git 與 .codex 受保護,AGENTS.md 除外第一趟對檔案下毒「安全」的第二趟奉之為權威帶著提升的權限往下執行共同的最後一步從行程或環境讀出真正的憑證然後送出去
三個彼此無關的 harness 繞過手法,同時被揭露。門各不相同 — 引號解析落差、未落實的允許清單加上 /proc 洩漏、在兩趟之間存活的可信指示檔。後牆卻一模一樣:每條鏈的結尾,都是從代理自身的行程或環境讀出一個真正的憑證,再送往某處。

相同的那部分

Novee 自己的總結是:「這些都不是單純的設定錯誤,而是正確的安全決策,在 交接點上崩解了。」就 harness 而言,這是正確的解讀。但請看每條鏈終結在 哪裡。

Claude 的 tac 讀出憑證,HuggingFace 計數器洩漏的是 API 金鑰。Gemini 的 /proc 缺口曝露的是父行程裡的祕密。Codex 提權後的第二趟,把環境 裡的 token 帶進了攻擊者控制的指示。三道互不相干的接縫以三種方式裂開, 而每一條的結尾都伸手去拿同一個東西:一個真正的祕密,就放在代理的行程或 環境裡,等著被讀走。

這正是所有這些攻擊共享的假設 — 只要能以代理的身分執行程式碼,憑證就在 手邊。而它幾乎總是在。ANTHROPIC_API_KEYGITHUB_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.mdAGENTS.md 及其變體)評分。Codex 兩趟之間那份被下毒 的 AGENTS.md,正是第二個偵測器被打造來抓的東西,而且它在主機上執 行,趕在模型依據該檔案行動之前。

這些設定裡有兩項預設開啟,而憑證代理機制根本不是一項設定 — 它就是 Bromure profile 持有祕密的方式本身。隱蔽通道也被補上了:GitHub Actions 日誌、HuggingFace 計數器、突兀的對外主機,全都得經過主機的代理伺服器, 而 Security Log 與 Trace Inspector 會記錄每個請求的主機、狀態與替換報告 — 那條洩漏了誘餌的側信道,同時也是一張你讀得到的清單上的一列。

普通的工作站行程持有的是真正的 API 金鑰、token、雲端憑證在環境變數、/proc 與磁碟上漏洞利用讀取它tac、/proc 或提權後的那一趟外洩送出的是可用的憑證而且它能寫入git push 抵達分支有毒的套件流向下游在 Bromure profile 裡行程持有的是brm_ 佔位符,在代理伺服器上替換真值從不進入 VM漏洞利用讀取它同樣的 tac、/proc、同一趟外洩送出的是誘餌而寫入被拒絕git-receive-pack 在代理伺服器被擋它跑過的 VM 可拋棄
同一個最後步驟,放在兩個地方看。在普通的工作站上,漏洞利用直接從行程讀出活的憑證,外洩送出的是真金鑰。在 Bromure 的 profile 裡,同樣的讀取對著佔位符成功,會毒害分支的寫入在代理伺服器被拒絕,代理跑過的箱子則可拋棄。

harness 還會繼續破

Novee 促成的三個修補都是好的,也都是窄的。Anthropic 修正了引號解析落 差;Google 改了 headless 信任模型;OpenAI 把兩趟拆開。每一個都關上了被 找到的那道特定接縫。但沒有一個改變三個漏洞利用的共同點:一份可用的憑證 就放在代理的行程裡,任人取用。下一個 harness 漏洞 — Novee 在另外上百個 儲存庫上找到了同樣的預設值,所以一定會有下一個 — 還是會伸手去拿它。

你可以用修補加上組態檢視回應每一次揭露,也應該這麼做。但修補關上的是一 個代理裡的一扇門,檢視則得一個儲存庫、一個版本地做。一個可用的漏洞利用 伸手去拿的那份憑證,在三個代理、在未來每一個漏洞裡都是同一份,而它也是 你能靠一個決定就移出攻擊範圍的唯一東西:把真祕密留在主機上,交給代理一 個佔位符,讓代理伺服器只對收件的那台主機產生真值。

安裝 Bromure Agentic Coding,給代理一個 — 連同一份憑 證 — 你輸得起的箱子。