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

關掉沙箱的開關就在沙箱裡

9 月 8 日公布的 CVE-2026-82533 是 DeepSeek Harness 上的 9.4 分:被關在沙箱裡的編碼代理,能用一道 shell 指令關掉自己的沙箱。這套 harness 在限制檔案寫入的作業系統沙箱裡執行代理的指令,同時把控制平面以 HTTP 介面暴露在回送位址上,而沙箱從來沒有覆蓋那裡。守著那個介面的檢查只讀呼叫端自己送來的 Host 標頭,從不看連線究竟從哪裡來。在 Bromure Agentic Coding 裡,代理在 VM 內部本來就不受限制,而它得去呼叫的控制平面,在它那一側根本不存在。

這一次完全用不上漏洞利用。被關住的代理對一個本機連接埠送出一道 shell 指令,請那個 關著它的沙箱把自己關掉,而沙箱同意了。

DeepSeek Harness 把編碼代理的指令放在作業系統的沙箱裡執行。這個沙箱窄而刻意:檔案寫 入只留在工作區與暫存資料夾裡,代理做的其他一切都是別人的問題。專案自己的命令列參考 文件就是這麼寫的。在預設設定下,「讀取與網路存取不受限制」。

這套 harness 還有一個網頁介面。它跑在同一台機器上、跑在一個本機 HTTP 連接埠上,而 harness 把它的位址交給代理的 shell,好讓工具能跟它說話。那個介面就是控制平面:它握著 一場工作階段的模式,包括那個叫作 danger-full-access 的模式,它會關掉沙箱、停掉核准 提示。

這兩個設計都很平常。把它們並排放在一起,代理就能用一道指令關掉自己的沙箱,因為沙箱 從來沒有覆蓋回送位址,而控制平面從來沒有檢查是誰在呼叫。

是 OX 的研究人員找到的。VulnCheck 在 9 月 8 日以 CVE-2026-82533 公布,CVSS 9.4。它在預設安裝上就成立,不需要網路暴露、也不需要任何憑證,直到 DeepSeek 在 8 月 27 日推出修補為止。

讀信封的那道檢查

那個介面完全沒有身分驗證。頂替它位置的是一個叫 isTrustedApiRequest 的函式, DevOps.com 引述了它做的事: 它「讀取 Host 請求標頭,若該值是回送位址的授權主體,或出現在設定好的 trustedHosts 清單裡,就放行」。

Host 標頭是用戶端自己寫的一行文字。它說的是用戶端認為自己正在跟哪個位址說話,而網 路上任何位置的呼叫端都能在裡面打上 localhost。連線真正的來源在下一層,在 TCP 的對 端位址裡,而 DeepSeek 的檢查從來沒讀過那個值。CVE 記錄把這個缺陷歸在 CWE-345Reliance on Untrusted Inputs in a Security Decision

坐在一個允許網路呼叫的沙箱裡的代理,對那個介面發了一次呼叫,把自己的工作階段設成 danger-full-access,核准設成 never。用 The Hacker News 的說法, 這次模式變更「不需要明確核准,因為它修改的是工作階段設定,而不是請求新的權限」。

核准系統照設計運作。代理從來沒有請求去做危險的事;它請求改一個設定,而那個設定管的 正是危險的事會不會被拿出來問。權限閘門檢視的是擺在它面前的那個操作。這次請求是一次 組態寫入,而組態寫入不在它的清單上。

一台機器、一個行程,兩個從未碰面的決定OS 沙箱限制了什麼編碼代理的 shell 指令寫入 → 只限 workspace + temp由作業系統強制,而且它守住了按設計就在範圍之外讀取:不受限制網路:不受限制,含 loopbackPOST http://127.0.0.1:…Host: localhost控制平面:本機 HTTP,無驗證isTrustedApiRequest(req)• 讀呼叫端的 Host 標頭• loopback 或 trustedHosts 就放行• 從不讀 TCP 對端位址產生的工作階段狀態mode = danger-full-accessapproval = never一次設定寫入,所以什麼都不問
整段逃脫。作業系統的沙箱把檔案寫入限制在工作區與暫存資料夾;讀取與網路呼叫,包括回送位址在內,按設計就在它的範圍之外。harness 的控制平面在一個本機 HTTP 連接埠上聽著,那個位址代理的 shell 早就知道。它的信任檢查讀的是呼叫端自己的 Host 標頭,從不檢視 TCP 的對端位址,所以來自沙箱內行程的請求,看起來就跟開發者發出的一模一樣。接著代理把工作階段模式寫成 danger-full-access,核准設定寫成 never。那是一次設定寫入,不是權限請求,所以什麼都不會跳出來問。

同一扇門,換個方向

一個信任呼叫端所送標頭的介面,並不在乎連線是從哪個方向來的。如果那個連接埠在網路上 搆得到,同一次呼叫從機器外面也一樣成立:一個沒有身分驗證的陌生人可以接管代理,把所 有存下來的對話全部匯出,不需要 API 金鑰,也不必為一次模型呼叫花掉任何一個 token。這 就是 CVSS 4.0 向量以 AV:N 開頭的原因,也是這個數字是 9.4,而不是某個本機而溫和的分 數的原因。

時間軸上有個值得記住的細節。兩位開發者在 8 月 13 日和 14 日,各憑自己的判斷,把這個發 現貼到 DeepSeek 的 GitHub 討論版上,那是在 OX 於 8 月 24 日確認之前,也在 CVE 存在之 前。這個儲存庫在 9 月 9 日有超過 216,000 顆星,卻沒有一份說明如何私下回報漏洞的安全政 策檔案,所以唯一還能放的地方就是一串公開討論。修補來的時候,是身分驗證:這個工具現 在會在啟動位址上印出一次性的權杖,瀏覽器拿那個權杖去換一份簽章過的 cookie,而對介面 的每一次呼叫都要帶著那份 cookie。

如果你在跑這套 harness,去查你機器上的版本,而不是專案發布的版本。第三方的桌面外殼會 自己帶一份。0.1.2-alpha.1 在 8 月 27 日只出現在 GitHub 上,8 月 30 日的 0.1.2-alpha.2 才是第一個帶著修補的 npm 版本,而某個 Windows 外殼一直停在 0.1.1-rc.2,直到 9 月 6 日才換到修補過的組建。

你的 harness 也長了一個

你可以把這件事歸檔成某個專案的臭蟲,然後往前走。但這個形狀會旅行,因為代理的 harness 正在長出一個個本機控制平面:給儀表板用的狀態伺服器、IDE 橋接、MCP 端點、一個在 localhost 上把差異畫出來的頁面。每一個都是你機器上的一個小小 HTTP 服務,而你的代理跑 的程式碼全部搆得到,因為代理就跑在那台機器上,而 localhost 的意思正是「那台機器」。

一旦控制平面坐到了它所控制的那個東西旁邊,決定結局的就只剩一個問題:被關住的一方, 能不能定址到關住它的那套設定?DeepSeek 的答案是能,靠的是一道對呼叫端一面之詞照單全 收的檢查。就算換上更強的檢查,它回答的仍然是一個本來就不該問得出口的問題。身分驗證 函式是程式碼,程式碼有備援分支,而今年是一場漫長的遊行,安全決策一個接一個地敗在沒 人走過的那條分支上。

在 Bromure 工作區裡,開關住在哪裡

Bromure Agentic Coding 從另一端開始。Bromure 的工作區讓代理不受限制。

在客體裡面,代理早就擁有 DeepSeek Harness 會稱為 danger-full-access 的東西。那是設計 上的靜止狀態。手冊也是這麼寫的:一個被提示注入或以其他方式亂來的代理「可以在客體 內部為所欲為,但它讀不到真正的 API 金鑰、無法用真正的 AWS 密鑰簽章、也取不出 SSH 私 鑰——這些東西在它那一側都不存在」。代理可以寫進檔案系統的任何地方、執行任何它想執行 的東西、綁定任何連接埠,所以它沒有任何可以再往上爬的模式了。邊界是一道 hypervisor 的 邊緣,而代理在那道邊緣的另一側。

因此客體根本沒有控制平面的位址。工作區的政策(護欄、憑證、防火牆規則、MCP 伺服器)住 在你 Mac 上 ~/Library/Application Support/BromureAC/profiles/ 底下的一個 profile.json 裡,而你在 Edit workspace 視窗裡修改它。客體沒有通往那個檔案的檔案系統 路徑,也沒有通往讀它的那個行程的網路路徑。

兩側透過 virtio socket 說話,那是跑在 VM 網路之外的主機對客體點對點橋接。一台工作區 VM 有八條,每條都有自己的差事:8443 把客體的 HTTPS 送到主機的代理伺服器,8444 是 ssh-agent 橋接,8445 餵給 AWS 憑證輔助程式,5800 承載終端機與檔案路徑,5010 轉送 OAuth 回呼。每一條只服務一個固定協定,沒有一條收 Host 標頭,所以呼叫端根本沒有一份 trustedHosts 清單可以靠嘴巴混進去。在 vsock 上,身分就是拓樸:位元組是從哪一條橋進 來的。那不是你能在請求裡打出來的東西。

harness:沙箱與它的設定,同一台機器沙箱裡的代理寫入受限網路不受限制知道介面的位址回送 HTTP守著的是呼叫端寫的標頭控制平面工作階段模式核准設定離它所管的東西只有一次請求Bromure 工作區:裡面全給,政策在另一側工作區 VM代理在這裡有完整存取權到處寫 · 什麼都跑 · 綁任何埠沒有可以再爬的模式它開的本機控制平面聽在這台 VM 的回送位址上這一側沒有真的憑證hypervisorvsock 8443只有 HTTPS沒有控制路徑macOS 主機每工作區代理伺服器:線上的邊界護欄 · 出口防火牆 · 換上假憑證:80 與 :443 由虛擬交換器轉走客體無從解除政策存放的地方~/Library/Application Support/BromureAC/…同意對話框畫在這裡,用 AppKit
同一個開關的兩種擺法。上:harness 的沙箱與管著它的控制平面跑在同一台機器上,所以代理透過回送位址就搆到了設定,而擋在中間的只有一道對代理自己所寫標頭的檢查。下:Bromure 的工作區在客體內部把一切都交給代理,並把政策放到 hypervisor 的另一側。虛擬交換器把客體對外的 HTTPS 轉進主機的代理伺服器,沒有任何環境變數可以解除;護欄、出口防火牆與憑證替換全都在那裡執行;而核准對話框畫在 macOS 上。客體對這些東西一個位址都沒有。

設不成 never 的核准

danger-full-access的後半段關掉了提示,這一半值得自己的答案。一個能讓自己的核准閉嘴 的代理,才是會讓我睡不著的那部分。

在 Bromure 的工作區裡,提示住在主機上。代理伺服器把它們舉起來的時候,請求已經離開 VM 了,所以客體裡的那場工作階段,身上沒有任何一個設定能壓下其中任何一個。使用前先問 會在一場工作階段中某份憑證第一次被用到時停下來,並給出有時限的授予:五分鐘、一小 時、這場工作階段的剩下時間,或是不允許。寫入政策設成寫入前先問時,每一次變更 操作都會被一個標題為 Allow write on "<scope>" from workspace "<name>"? 的對話框攔下來,上面顯示原原本本的 操作內容、SQL 敘述本身,或 REST 呼叫的 METHOD /path允許一次根本不建立授予,所 以下一次寫入還是會問。授予住在記憶體裡,工作階段視窗一關就消失。

護欄那一頁用一個子句說完了這個性質:寫入政策「在代理伺服器裡強制執行,所以 VM 裡被攻 陷的代理繞不過去」。底下的出口防火牆也是一樣的做法:一張有序的規則表,帶著一個可以設 成 DenyUnmatched traffic 控制項,套用兩次——一次在虛擬交換器上,依目的地 IP 與從 DNS 側錄到的主機名;一次在代理伺服器上,依 TLS 伺服器名稱,web 規則還加上 HTTP 方法。規則的修改不必重開就會送到執行中的工作階段。

無人看顧的執行會往安全的一邊倒。透過 SSH 或自動化以無介面方式驅動的工作區,會在自己 的 tmux 裡收到同樣四個選項的文字提示,而沒有回答就等於拒絕。那裡最壞的結果,是一次被 擋下的呼叫,加上 Security Timeline 上的一列紅字。在這個 CVE 裡,代理把核准設成 never,提示就消失了。

如果你在 Mac 上跑代理的 harness

去問它的本機介面有哪些、誰可以呼叫它們。在 Bromure 的工作區裡, bromure-cli vm ports <workspace> 會印出客體當下正在聽的 socket,附上連接埠、協 定、位址與行程,而且會標出只綁在回送位址上的那些。VM 儀表板的 Listening Ports 卡片 顯示的是同一份東西。這份清點正是這個 CVE 賴以成立的那個問題,而一道指令就答完了。

如果那個介面也朝外

CVE-2026-82533 的遠端那一半,需要連接埠搆得到。工作區的 VM 跑在一個私有 NAT 網路 上:從你的 Mac 搆得到,但它們「不會暴露在你的實體區域網路上,而且除非你明確發布某 個服務,否則來自別處的連入連線是不可能的」。一個咖啡店網路根本繞不過去的、沒有身分 驗證的代理控制埠,會讓你有餘裕照自己的節奏上修補。

可以撤銷的關押,只是一種偏好

DeepSeek 出了一道弱檢查,並在 OX 確認後三天修好。留下來的,是那道檢查在守著什麼。由 一個行程自己的執行環境,繞著這個行程畫出來的邊界,是這個行程可以拿來談判的邊界:它 有位址、有 API,還有一個裡頭帶著欄位的設定物件。在那個欄位的背後某處,跑著一條決定這 個呼叫端能不能寫它的程式碼路徑,而這一類的程式碼路徑,離變成裝飾品只差一個糟糕的預 設值。

把邊界畫在行程底下,就沒有對手可以談判了。Bromure 工作區裡的代理握有 root、握有整個 檔案系統,還能在任何連接埠上起任何它想起的服務。它的 API 金鑰是誘餌,它通往網路的唯 一路徑是一條通往你 Mac 上代理伺服器的 virtio socket,而裝著它權限的那個檔案,放在它讀 不到的地方。在線的那一側把一切都交給代理,你就不必再守那條線了。

編碼代理還會繼續長出本機控制平面,因為控制平面正是你打造儀表板、IDE 橋接或差異檢視器 的方式。於是每個專案都得回答一個問題:它的代理所執行的程式碼,跟管著那個代理的設定, 是不是在線的同一側。答錯了,還撐著的就只剩身分驗證,而一個 9.4 分就是這樣落到一道 shell 指令上的。 裝上 Bromure Agentic Coding,把開關放到你的代理搆不到的地方。