隔離把那個指令跑了
2026 年 8 月 10 日,Manifold Security 公布了 Cursor CLI 代理的一個缺陷:那個讓代理在隔離的 git worktree 裡啟動的旗標,會從你剛剛複製下來的儲存庫讀一個 JSON 檔,再把內容原封不動交給 shell——發生在 Workspace Trust 詢問之前,而且即使你開了沙箱,它也在沙箱之外。沒有模型,沒有提示注入,沒有勸說。Bromure Agentic Coding 提供同一個 worktree 原語,但儲存庫沒有任何地方可以放進一條指令,而且整件事發生在一台早在儲存庫抵達之前就存在的 VM 裡。
你輸入的那個旗標,意思是「把這個隔離起來」。就是那個旗標,以你的身分、在你的 機器上、在任何東西問你信不信任這個儲存庫之前,執行了儲存庫的 shell 指令。
2026 年 8 月 10 日,Manifold Security 的 Francisco Rosales 公布了
Cursor 命令列編碼代理的一項發現,
三天後 The Hacker News 在
ThreatsDay 匯整
中跟進報導。概念驗證打開的是一台計算機。那是 Manifold 詳列的那份清單的客氣版
本:讀 ~/.ssh、從環境取走雲端憑證、開一個反向 shell、寫下持久化。
請把它當成一種投遞方式來讀,而不是當成一份酬載。沒有人注入任何東西,沒有人勸說 任何模型,沒有哪句聰明的話藏在 README 裡。儲存庫裡一個被追蹤的 JSON 檔指名了一 條指令,而代理裡那個唯一職責就是隔離的部分,把它跑了。
一個旗標、一個 JSON 檔,和錯誤的順序
cursor-agent 是 Cursor 編碼代理的終端機版本。把代理放到你的工作樹上會讓人緊
張,所以這個 CLI 提供了圍堵手段,並寫進它自己的參數說明:
-w, --worktree [name] Start in an isolated git worktree at
~/.cursor/worktrees/<reponame>/<name>
全新的 worktree 是一份乾淨的簽出,所以它沒有你的任何建置產物。為了讓它可用,
CLI 在建立 worktree 時會預設執行一個設定步驟。那個步驟會從它剛剛簽出的儲存庫裡
讀 .cursor/worktrees.json,並把 setup-worktree 的值直接交給 sh -c:
{
"setup-worktree": "<any shell command>"
}
Manifold 對「那個值和 shell 之間隔著什麼」的描述只有三個詞:「沒有解析、沒有白 名單、沒有詢問。」
.cursor/worktrees.json 是一個普通的被追蹤檔案。它會隨著一次平常的 git clone
一起到來,就像 README 或一個鎖定檔一樣。在 2026.07.23-e383d2b 之前的組建
裡,worktree 的建立與設定發生在工作區解析的過程中——而工作區解析會在那條負責顯
示 Workspace Trust 對話框的程式路徑之前就結束。所以指令先跑。在 Manifold 報告
附上的錄影裡,終端機還在印 Running worktree setup commands…,計算機就打開了,
接著才出現那個問你信不信任這個目錄的對話框。
Cursor 對那個對話框的用途說得很明白:儲存庫能控制的任何東西,都不該在你接受之
前執行。當有東西真的跑了,業界對這類錯誤有個名字——信任前執行——而 Cursor 之前
就在同一個目錄裡修過一次。2025 年,儲存庫附帶的 .cursor/mcp.json 會在你一打
開專案時就自動啟動它所設定的伺服器。那件事變成了
CVE-2025-64109,
評為 High,CVSS 8.8。同一個 CLI 對 .cursor/cli.json 過於寬鬆的處理則變成了
CVE-2025-61592,
一樣是 High,一樣是 8.8。當時 -w 這條 worktree 路徑還不存在。它在那次修補的五
個月後才出貨,帶著同一個原語,而且沒有任何關卡。
Manifold 在 7 月 20 日回報。Cursor 在 7 月 23 日出貨了重新排序:信任對話框現在 會先繪製,設定指令則要等到工作區被信任之後。7 月 29 日,Cursor 以僅供參考 (Informative)結案,理由是利用這個問題需要使用者去複製一個由攻擊者控制的儲存 庫。值得記住的是 Manifold 的回答。複製儲存庫 正是這個產品存在的理由, 而它同樣也是 CVE-2025-64109 的前提條件——那個 Cursor 評為 8.8 並修補了的錯誤。 複製描述的是投遞方式。缺陷在別的地方。
你打開的那個設定,到不了那條路徑
還有第二條腿,而且它在修補後存活了下來。
那個設定步驟是在一個寫死的 insecure_none 沙箱政策底下執行的。那是 Cursor 自己
給這個值取的名字:在 sandbox.json 裡,type 接受 workspace_readwrite(預
設)、workspace_readonly 或 insecure_none,最後一個會完全關掉沙箱。worktree
的設定路徑被釘死在最後一個上。傳 --sandbox enabled 也改不了它。Manifold 這樣
描述目前的組建:更新「關上的是信任前的那扇窗,不是沙箱的那個缺口」。
把這兩條腿並排放在一起,你會得到一件比這個產品活得更久的事。信任關卡是一段序列 裡的一步,所以它可能落在錯的位置。沙箱是一個設定,所以某條程式路徑可以讓自己豁 免。worktree 帶著隔離這兩個字,所以使用者從中讀出了圍堵。這三件事都由 Cursor 自 己的程式碼決定,在它自己挑的時機,在它們本該約束的那個行程內部。那正是兩週前 打敗某個函式庫安全旗標的同一種失敗,也是 七次沒有任何東西逃出沙箱的沙箱逃逸背後 的那一種。
一種與你共用帳號的隔離
-w 隔離的是工作樹。它給代理一份自己的簽出,讓它不會踩壞你尚未提交的工作——這
是個真實的問題,也是個真實的解法。沒有人是為了隔離機器才做它的。worktree 住在
~/.cursor/worktrees/,在你的使用者底下,帶著你的環境、你的 ~/.ssh、你的
shell 設定檔、你的雲端憑證,而你的鑰匙圈就在一次系統呼叫之外。Manifold 列出的
「設定指令本來可以做什麼」,讀起來就像那個家目錄的財產清冊。
所以:一個你還沒讀過的儲存庫選了一條指令,而你為了安全才呼叫的那個功能,正是 執行它的那個。一個 JSON 檔和一個 shell,模型從頭到尾坐在場邊。
關於代理安全的討論,大半已經飄向模型。它好不好騙、能不能被說服、有沒有讀到不該 讀的東西。這些問題都重要, 我們也寫了很多篇。與此同時,2026 年要在開發者筆電上執行程式碼,最穩的辦法仍然是把它寫進某個工具啟動時會讀的檔 案,然後等某個人去複製。
一個沒有地方放指令的 worktree
Bromure Agentic Coding 提供同一個原語,因為這個原語是好的。
在儲存庫分頁按 ⇧⌘G,輸入一個任務名稱,挑一個代理,Bromure 就會從目前的提交切出
一條 wt/<slug> 分支,把它簽出到 ~/.bromure/worktrees/<repo>/<slug>,在那裡
開一個分頁,並用你的提示啟動代理。好幾個任務、好幾條分支、好幾個代理,一個儲存
庫——艦隊模式。
Bromure 的設定步驟和 Cursor 的工作一樣:乾淨的簽出缺了代理需要的那些被 gitignore
的檔案,所以總得有東西把它們搬過來。差別在於儲存庫被允許就此說些什麼。儲存庫可
以附一個 .worktreeinclude 檔,其中每一行非註解的內容都是相對於主 worktree 根
目錄的路徑。Bromure 用 cp -a 逐一複製,而且只在來源存在、目的地不存在時
才複製。那個檔案裡沒有任何欄位裝得下一條指令,所以沒有需要正確排序的 sh -c,
也沒有可以搞錯的順序問題。一個充滿敵意的 .worktreeinclude 最壞也只能要求把某
個檔案複製進簽出裡。整套詞彙就這麼多。
更大的差別在於這一切發生在哪裡。
把那條指令跑起來。看看它找得到什麼。
拿 Manifold 那份清單,讓它走過一個設定檔,並且把一切都讓給攻擊者——信任之前、沒 有沙箱、你高興的話還可以在客體裡當 root。
讀 ~/.ssh。 那裡沒有東西可讀。一個設定檔的私鑰留在主機上。VM 拿到的
SSH_AUTH_SOCK 指向 /tmp/bromure-agent.sock,透過 vsock 橋接到你的 Mac 上一
個屬於該設定檔的代理程式,而 Bromure 刻意不去接上你 macOS 的 launchd 代理。代理
協定裡有「列出我的公鑰」和「簽署這個挑戰」這樣的請求。它沒有任何一種請求的意思
是「把私鑰交出來」。打開 Require approval to use,每一次簽章都會變成主機上
的一個對話框,附帶一個有時限的授權——五分鐘、一小時、這場工作階段的其餘時間。
從環境取走雲端憑證。 它們就在那裡,看起來也很對,而它們是假的。設定檔的
Credentials 面板裡的每一項,都是以佔位值的形式注入,再由主機端的代理伺服器在線
路上換成真值:通用 API 金鑰用 brm_…、一份帶著用完即丟客戶端憑證的合成
~/.kube/config、~/.docker/config.json 裡一個假的 base64 區塊、
~/.git-credentials,以及在主機端重新簽章、對任何想繞過代理伺服器的人回
InvalidSignatureException 的 AWS 材料。竊取會成功,然後
什麼值錢的都沒帶回去。
開一個反向 shell。 現在攻擊者得把某樣東西送過一條線,而那條線屬於主機。VM 每一個對外請求,都會用 Aho-Corasick 自動機與這個設定檔鑄出的誘餌逐一比對——標頭 與主體,整個請求,而不只是看起來像憑證的那些部分。一個誘餌前往它被鑄造時的範圍 之外的主機,正是一台機器正在把它根本不該知道的東西帶出去的簽名。代理伺服器會在 目的地看到任何一個位元組之前中止上游呼叫,回一個 451 給客體,暫停 VM,把凍住的 畫面染紅,並發出一則點名該憑證、它原本被鑄給哪台主機、以及它實際去了哪台主機的 警報。由你選擇:關機、留存供調查——磁碟映像、家目錄、共享資料夾,打包並標記起 來,讓這個設定檔在被清除之前不會再開機——或是繼續。
寫下持久化。 這台機器的壽命就是一個任務。Erase home 會重置
/home/ubuntu,Reset to base 會重新複製工作區的系統磁碟。
與此同時,你原本要的工作照樣往前走。代理審視儲存庫、跑測試、開拉取請求。儲存庫 的那條指令執行了——在一個「執行」就是它唯一能做的事的房間裡。
打補丁涵蓋不到的那部分
Manifold 的文章裡還有一個細節,而它的保存期限最長。Cursor 沒有為這條 worktree 路徑發布任何資安公告,也沒把它寫進七月的變更紀錄,所以修補是夾在一次例行組建裡 出貨的。任何在受影響版本上的人,都無從得知更新關掉的是一條信任前執行的路徑。而 你今天也無從得知,你筆電上哪個工具還開著這樣一條路徑,因為那條路徑永遠是某個工 具啟動時會讀、而還沒有人稽核過的某個檔案。
Cursor 三天就把這個關掉了,很快。Cursor 在 2025 年也關掉了 mcp.json 那個版
本,然後五個月後來了一個帶著同一個原語的新功能。把功能一路塞進啟動序列,看起來
就是這樣:每多一種能力就多一步,而每一步都是在某個星期四要多排對一次的一件事。
Hypervisor 不是那個序列裡的一步。它不讀 .cursor/worktrees.json,不讀
.worktreeinclude,也不讀你儲存庫裡的任何東西。它在複製之前就在那裡了,它沒有
一個能讓某條程式路徑釘死成 insecure_none 的政策欄位,而它的保證——這台機器是
拋棄式的、這些憑證是假的、這條線有人在看——
在某個繞過手法被公開的那天,和它被修補的那天,是一樣的。
繼續複製你還沒讀過的儲存庫吧。審視不熟悉的程式碼就是這份工作,把它交給代理則是 養一個代理的意義。只要別再讓這場審視發生在你放 SSH 金鑰的同一個帳號裡就好。 安裝 Bromure Agentic Coding,給每個任務自己的分支、自己的簽 出、自己的拋棄式機器,那麼下一次某條啟動路徑被發現會照著某個 JSON 檔說的話執行 任何東西時——而這一定會發生——它會在一個為它而建的房間裡執行。