代理從未離開沙箱
2026 年 7 月 20 日,Pillar Security 公布了橫跨 Cursor、OpenAI 的 Codex CLI、Google 的 Gemini CLI 與 Antigravity 的七個沙箱逃逸。沒有一個真正突破了沙箱。代理待在裡面、遵守每一條規則,只是寫下一個普通的檔案——一份 hook 設定、一個虛擬環境、一項 git 設定——而主機上一個受信任的工具讀取了它並自行執行。沙箱守住了;逃逸依然發生。Bromure Agentic Coding 把界線畫在這一招無處落腳的地方。
先前每一則逃逸故事都在講牆被攻破。這一則講的是牆守住了,逃逸卻依然發生。 代理服從了沙箱,寫下一個它獲准寫入的檔案,而牆另一側一個受信任的程式撿起 那個檔案並執行了它。
編碼代理在沙箱中執行,是為了當它做出魯莽之事時——而它一定會,因為它整天讀取 不可信的文字,並且大多都相信——傷害會止於沙箱的牆。這就是那個承諾。2026 年 7 月 20 日,Pillar Security 公布了這個承諾破裂的七種方式,橫跨最常用的四個代理:Cursor、OpenAI 的 Codex CLI、Google 的 Gemini CLI 與 Antigravity。 BleepingComputer 在同一週作了報導。
令人意外的數字不是七。這七者共通之處在於:用研究人員自己的話說,「在幾乎所有 案例中,代理都不需要直接突破沙箱。它只需要寫下某個東西,讓沙箱外一個受信任的 元件稍後去執行、載入、掃描,或當作安全來對待。」
這一招——待在裡面、寫下檔案、讓主機執行它
想想編碼代理的沙箱實際上圍住了什麼。它圍住了代理的行程——執行模型決策的那個
東西。它並不圍住代理的檔案,因為整份工作就是寫檔案:原始碼、設定、建置腳本。
這些檔案落在你其他工具所讀取的同一顆磁碟上。而你其他的工具並不在沙箱裡。你
編輯器的 Python 擴充功能不在沙箱裡。你的 git 不在沙箱裡。Docker 守護行程不在
沙箱裡。它們信任磁碟上的東西,因為直到不久前,唯一往那顆磁碟寫入的就是你。
所以代理從不碰那道牆。它就在該寫的地方寫下一個檔案,然後等著另一側有什麼東西 去讀它。Pillar 的七個逃逸,就是這同一招的七個版本:
一份會執行的 hook 設定
在 Cursor 中,代理寫下一份工作區的 .claude hook 設定。Hook 本就用來在
編輯器事件時執行指令——於是那個檔案裡的指令便執行了,在沙箱之外。獲配
CVE-2026-48124,已在 Cursor 3.0.0 修復。
一個被掉包的 Python 直譯器
代理編輯專案虛擬環境內的直譯器。編輯器的 Python 擴充功能——在沙箱之外—— 稍後叫用它,被掉包的執行檔便執行了。以 GHSA-p9g2-cr55-cw9c 追蹤。
一個因名稱而被信任的 git 指令
Codex CLI 的「安全指令」允許清單放行了一次 git 叫用,因為名稱看起來
無害,卻沒讀取使其危險的引數。已在 Codex CLI 0.95.0 修復。
一個等於第二台機器的守護行程
在數個代理上,Docker socket 從沙箱內部就能觸及。一個有特權的本機守護行程, 就是整整第二個可以執行程式碼的地方,就在邊界外側。以 GHSA-v4xv-rqh3-w9mc 追蹤。
Antigravity 又加了兩個相同形狀的——一份漏掉某個案例的 macOS Seatbelt 拒絕清單, 以及一份代理寫下、IDE 之後自行執行的 VS Code 任務設定。兩者都被評為較難達成, 但都與其餘的押著同一個韻。
為何逐一修補並不能封住這個形狀
這些每一個都拿到了修補,而且都是好的修補。Cursor 推出了 3.0.0,Codex CLI 推出 了 0.95.0,Docker socket 被鎖了起來。如果你用這些工具,就去更新它們。但看看在 這裡一個修補必須做到什麼。它必須找出代理能寫、而某個別的程式會當作指令看待的 每一個檔案——hook 設定、直譯器路徑、git 中繼資料、任務定義、lint 規則,以及下 一季會冒出來的任何東西——並把每一個都當成特例來處理。那是一份拒絕清單,而 Pillar 把拒絕清單列為四個反覆出現的失效模式之首,因為「一個從『預設允許』出發 的沙箱設定檔,必須記住作業系統所公開的每一項危險操作」。作業系統不斷加入新 操作。這份清單永遠列不完。
更深的理由,是報告裡一句讀來像定義的話:「如果一個代理能寫下系統未來的輸入, 那它從一開始就沒被裝進沙箱。」在一台代理與其他一切共用磁碟與一組受信任守護 行程的機器上,圍著代理行程畫出的界線,是圍錯了東西。他們寫道,波及範圍「不是 代理的行程;它包含代理能寫、而主機之後會信任的一切」。在開發者的筆電上,那 幾乎就是一切。
Bromure 把界線畫在哪裡
Bromure Agentic Coding 不試著把危險檔案一一列舉,也不試著把 hook、虛擬環境和
任務執行器教給沙箱。它移動界線。每個設定檔的代理都在 Apple Silicon 上一台拋棄式
Linux VM 裡執行,與 macOS 隔著一道虛擬機管理程式。在這個模型裡,「沙箱外那個
受信任的工具」——你編輯器的 Python 擴充功能、你的 git、Docker 守護行程、IDE
的任務執行器——並不在一道權限牆的另一側。它在一道虛擬機管理程式的另一側,而且
根本不讀取這台 VM 的磁碟。
這就是全部的差別。Pillar 那一招需要兩樣東西在同一個地方:一顆代理能寫的磁碟,
以及一個會讀那顆磁碟的受信任程式。把代理的磁碟放進 VM 裡,第二樣就沒了。代理
可以寫下一份 hook 設定、掉包一個虛擬環境直譯器、埋下一份任務定義——七個逃逸裡
的每一個檔案——而不會有任何不在沙箱裡的主機工具監看那個檔案系統來把它撿起。
任何被執行的東西,都在箱子裡、以拋棄式的 ubuntu 使用者身分、在一台什麼都不
裝的機器裡執行。
逃逸還有值得點名的後半段,因為 Bromure 也回應了它。假設代理寫下的某個檔案真的
被 VM 內的某個工具執行了——執行程式碼的目的,通常不是偷走什麼,就是抵達某處。
這兩者在這裡都是死路。程式碼衝著那些讓這趟行程划算的憑證而去——Anthropic 的
鑰匙、AWS 的鑰匙、GitHub 的權杖——找到的卻是誘餌:主機上一個
憑證仲介注入像 brm_… 這樣的預留位置、
一份合成的 kubeconfig、一把拋棄式 SSH 鑰匙,並且只在網路邊界、只在送往你早已
核准之目的地的請求上,才把真正的值換上去。而對外那一步——把戰利品外送,或抵達
第二台主機——會穿過主機代理,在那裡真正的目的地在出去的路上受到管制,而針對
這個設定檔所代理的雲端與 git API 的破壞性操作——一次 delete、一次 drop、或一次
terminate——會撞上一道無論代理被怎麼慫恿都能拒絕它的防護欄。
在這一切之前,還坐著一層從根源上扣住這些逃逸的防線。它們每一個都始於一次 注入——代理讀到的某個檔案或工具結果裡的一條惡意指令,一開始就叫它去寫下那份被 下毒的設定。Bromure 會在模型據以行動之前,用一個裝置端的 注入偵測器為那份不可信的內容 評分。它攔下其中大部分,而一個夠新穎的酬載仍可能溜過單一個分類器,這正是為 什麼它坐在拋棄式箱子的前面、而不是取而代之。
界線一直圍錯了東西
Pillar 那一週留下的長久教訓,不是一份七個待修補臭蟲的清單。而是:把代理行程 裝進沙箱——在一台這個行程與你所擁有的一切共用磁碟、共用一組受信任工具的機器 上——是把界線圍錯了東西。如果代理能寫下某個已經在外面的東西的輸入,它根本不 需要逃出去。
修補那些已知的檔案是對的,你也該做。但那是一場對抗每一種未來格式的競賽——某個 主機工具將來會決定去信任的格式——而這場競賽不會結束。Bromure Agentic Coding 退出了這場競賽。它假設代理終將被慫恿去寫下那份下毒的檔案,並確保當某個工具 讀取它時,那個工具是在一個拋棄式箱子裡——秘密以誘餌相待、線路上設有關卡——而 不是在你那台抱著你鑰匙的筆電上。這就是差別:一道你得不停修補的牆,對比一條 畫在低一層、寫下卻無人讀取的界線。安裝它,給你的代理一台 不是你的、輸了也無妨的機器。