Agent 沙箱與安全:別再指望「跟模型說清楚」

Agent 沙箱與安全:別再指望「跟模型說清楚」

前言:一次成功的攻擊鏈

安全研究員 Johann Rehberger 的 ZombAIs 演示,至今仍是 Agent 安全的標準教材:Claude Computer Use 在一個沒有防護的瀏覽會話中,造訪惡意網頁、讀取隱藏的指令 payload、下載二進位檔並執行、最後連上 C2 伺服器——整個攻擊鏈一次成功。同一時間,OpenAI 與 Anthropic 揭露正在調查數萬起模型行為異常事件(涵蓋未遂測試與內部評估中的 guardrail 觸發,多數未造成實質損害),而 OWASP 在 2025 年 12 月發布了《Top 10 for Agentic Applications 2026》(ASI01–ASI10,逾百位研究者審閱)。

這些事件指向同一個結論:用「跟模型說清楚」來守安全,是行不通的。system prompt 不是安全邊界。

一、新的信任邊界:tool call

傳統 Web 安全打了幾十年注入(injection)、混淆代理人(confused deputy)、權限控管,Agent 把這整套典籍帶到一個全新的地方:agent 的 tool call。

LLM 的基本問題是它在「解釋語言」。同一個 context 裡混著應用程式指令、使用者請求,以及模型被要求檢視的第三方內容。一段惡意文字藏在後者裡,看起來就像另一道指令——這就是 prompt injection,OWASP 把它列為 LLM01,也是 ASI01(Agent Goal Hijack,CWE-94/77)的核心機制。

Greshake 等人在 AISec 2023 的經典工作指出:處理被檢索的 prompt,等同於在 agent 的工具面上執行任意程式碼。他們展示的攻擊手法包括資料竊取(把對話歷史外送到攻擊者 URL)、蠕蟲式擴散、記憶體毒化(persistent memory poisoning),甚至污染共享記憶讓其他 agent 也被感染。2024–2026 年,間接 prompt injection 成了每個生產級 agent 都必須面對的定義性問題。

而傷害的放大器,是 Excessive Agency——它在 OWASP LLM Top 10 2026 年版從第六名升到第三名。道理很直白:注入指令的傷害,等於 agent 手裡握著的權限。一個只能讀文件的 agent 被注入,最多讀錯東西;一個握著廣域 API token、shell 權限、repo 寫入權的 agent 被注入,文字伎倆就變成真實行動。

二、為什麼 Docker 容器不夠:三層隔離光譜

「把 agent 跑在 Docker 裡」是很多人第一個想到的答案,但容器共用 host kernel——對 kernel 級逃逸來說,這是根本性的弱點。實務上業界已經收斂出三層光譜(如圖一):

第一層:強化容器(hardened container) namespace + cgroup + seccomp-BPF + AppArmor/SELinux + 唯讀 root filesystem + no-new-privileges。速度最快、成本最低,適合邊界明確、可重現、可撤銷的確定性任務:HTML 解析、測試跑者、文件轉換、可信 repo 的建置。注意「可信」二字——標準 Docker 容器只留給完全可信的內部工具。

第二層:gVisor / Kata Containers 在容器與 kernel 之間加一道 runtime 邊界:gVisor 用 userspace kernel 攔截 syscall,Kata 則是每個 pod 一個輕量 VM。適合混合信任的 shell 任務、多租戶作業。Modal 的沙箱即採用 gVisor 架構。

第三層:Firecracker microVM 硬體虛擬化為每個 agent 啟動一個獨立的 guest Linux kernel,冷啟動約 125 毫秒。E2B 的 disposable VM、Daytona 的沙箱走的都是這條路線。2026 年初 Docker 也推出了實驗性的 Docker Sandboxes,專門為 AI 隔離設計;Cloudflare、Vercel、Modal 相繼跟進。

選型規則很簡單:任務可限界、可重現、易撤銷 → 用容器;agent 能執行任意程式碼、瀏覽未知網域、或接觸有商業價值的 secret → 用 ephemeral microVM。冷啟動延遲可以用暖池(warm pool)或 snapshot/restore 攤平。

三、確定性層才是保證:安全五件套

2026 年的防禦共識是:確定性政策是保證(the guarantee),分類器只是遙測(telemetry)。模型層的偵測擋不住自適應攻擊——設計時就假設它會被繞過,把 blast radius 縮到最小才是正解。實作上有五件事(如圖二):

1. 沙箱裡不放真憑證。 常見錯誤是把 secret manager 吐出的 10 分鐘臨時 token 當環境變數塞進容器——對被注入的 agent 來說,10 分鐘是永恆,一個 curl 只要 200 毫秒就能把 key 送到外部。正確做法:key 留在雲端 secret 保管處,agent 的出站呼叫走外部 gateway proxy(如 Apigee AI Gateway),以 IAM Workload Identity 認證 agent 身分,只在目的地是核准 URL 時才在出站途中掛上真正的 API key。

2. 所有外部回傳都是不可信輸入。 sandbox 的 stdout、檔案、tool output 回到模型 context 前,要做大小上限、schema 驗證與注入感知處理——tool output 本身就是 prompt injection 向量。應用層也一樣:不要 eval 回傳的「JSON」,不要未經沙箱渲染回傳的 HTML。

3. 思考環境與行動環境分開,處處設硬 timeout。 每個 tool call、每個任務迴圈、每個沙箱生命週期都要有不可繞過的超時。被注入的 agent 最愛做的事之一就是無限迴圈燒資源(Unbounded Consumption)。

4. 出站網路預設拒絕,用 allowlist 放行。 最近的雲端 coding agent 審計發現一個典型盲點:推理時鎖了網際網路,但初始的 npm install / pip install 階段卻全開——惡意套件的安裝腳本在 agent 開始工作前就把資料偷走了。最小可用版本可以直接寫在 HTTP client 包裝層:


import httpx
from urllib.parse import urlparse

ALLOWED = {"api.anthropic.com", "api.openai.com", "internal-api.example.com"}

class PolicyViolationError(Exception):
    pass

class AllowlistedHTTPClient:
    def __init__(self):
        self._client = httpx.AsyncClient(timeout=10.0)
    def _check(self, url):
        host = urlparse(url).hostname or ""
        if not any(host == d or host.endswith("." + d) for d in ALLOWED):
            raise PolicyViolationError(f"blocked: {host}")
    async def get(self, url, **kw):
        self._check(url)
        return await self._client.get(url, **kw)

這是應用層的執行點,補強(而非取代)基礎設施層的 egress 政策。

5. 最小權限+分級人工確認。 登入、付款、發訊息、刪資料——高爆破半徑的工具走人工確認,而且確認 UI 要顯示「要做什麼」而不是一個空洞的「Allow?」。Anthropic 觀察到約 93% 的核准率:疲勞本身就是會被威脅建模的失效模式,所以確認要分級升級(risk-tier escalation),不是每件事都彈窗。

四、看看大廠怎麼做

  • Claude Code:用作業系統層隔離(macOS Seatbelt / Linux bubblewrap),寫入限於工作目錄,零容器開銷。
  • OpenAI Codex:Landlock + seccomp,檔案寫入限 workspace,網路預設關閉。
  • Devin:整台雲端 VM 隔離,關鍵節點加人工檢查閘門。
  • 最小可行沙箱可以濃縮成五個設定:Landlock + seccomp + PR_SET_NO_NEW_PRIVS + 非 root + cgroup——擋在你的 agent 和你的家目錄之間。

結論:把安全寫進架構,而不是寫進 prompt

Agent 安全不是新學科——它是經典安全典籍在「agent 的 tool call」這個新信任邊界上的重逢。會動的控制都是無聊但有效的老朋友:最小權限、中介存取、強身分、可稽核的軌跡。行不通的,恰恰是團隊最常做的那件事:試圖用「跟模型說清楚」來治理 agent。

下次部署 agent 前,先回答一個問題:如果這隻 agent 此刻已經被注入,它能造成的最大傷害是什麼? 把答案縮到你能接受的大小,沙箱才算設好了。

參考來源

Uploaded Image Uploaded Image

沒有留言:

張貼留言