AI 開發

NVIDIA 發布 AI Agent 安全平台:OpenShell、Sentry 如何限制 Agent 的 JSON Tool Calls?

閱讀約 16 分鐘

模型仍然只填 JSON。2026 年 9 月 28 日,NVIDIA 把邊界放到模型外面:OpenShell 在沙箱代理裡看 tools/call 的工具名,Sentry 在 BlueField-4 上做帶外隔離。允許 lookup_order 不等於允許任意 order_id。

閱讀前速覽

層 官方事實 誰擋住呼叫
OpenShell Apache 2.0。沙箱加核心隔離。代理檢查沙箱發往 MCP 服務的請求體 按工具名 allow / deny。不匹配引數
Sentry BlueField-4 上的帶外看門狗。越出軟體邊界就在毫秒級隔離。參考設計,可選 硬體層停執行。不填 JSON
策略證明 閘道器裡的 prover。新的帶憑據可達、新 HTTP 方法、雲後設資料會擋住自動批准 改策略之前。不是執行時的 Schema
宿主 Schema 文件寫明:允許的工具接受任意引數 執行前再驗 arguments

事實來自 2026-09-28 的 NVIDIA 新聞稿、技術部落格,以及 OpenShell 策略文件。訂單 A-1042 是虛構的。下面的 JSON 是文件 YAML 的同一組欄位,不是 Sentry 的未公開線級格式。

OpenShell 擋工具名,Sentry 擋越界執行

Open Agent Safety Platform 是兩塊,不是又一種聊天權限。第一塊是 OpenShell,Apache 2.0,現在廣泛可用。它給跑在 CPU 上的 Agent 一個沙箱:核心管檔案、系統呼叫和網路,代理再看離開沙箱的 HTTP。MCP 端點用 protocol: mcp,檢查沙箱發往服務端的請求體,能按方法和 tools/call 的工具名放行或拒絕。第二塊是 Sentry,參考設計。它跑在 BlueField-4 DPU 上,帶外、不在 Agent 夠得著的地方。Agent 越出軟體邊界,Sentry 在毫秒級隔離並停掉。在 Vera Rubin POD 裡,這塊 DPU 位於節點通往模型的唯一路徑上。第三,引數不在這兩層裡。OpenShell 寫明:工具引數匹配尚未支援,允許的工具接受服務端肯收的任意引數。

  • OpenShell:lookup_order 可以放行,refund_order 寫進 deny_rules。
  • Sentry:可選的硬體層。它關聯互動、策略決定和工具訪問,並做身份核驗。它不代替工具名單。
  • 宿主:A-1042 是否合法,仍用 Schema 驗 arguments。

會話裡的 allow / ask / deny 是另一道門,見 Coding Agent 的權限模型。MCP 的 tools/call 長什麼樣,見 Coding Agent 如何呼叫 MCP。實驗室越出評測環境的事件,站內已經寫過,見 Agent 安全危機與 JSON 驗證。本篇不重寫那些事件,只拆 OpenShell 和 Sentry 怎麼擋住一次工具呼叫。

代理看見的是 tools/call,不是模型的散文

OpenShell 解析的是沙箱程序發往 MCP 端點的 JSON-RPC 請求。虛構訂單,主機名用 orders.example.com:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "lookup_order",
    "arguments": { "order_id": "A-1042" }
  }
}

它核對的是 method 和 params.name。預設還要求工具名匹配 ^[A-Za-z0-9_.-]{1,128}$,這就是 mcp.strict_tool_names,預設 true。通配的 tool 匹配器要求這個開關保持開啟。arguments 裡的 order_id 不參與這條策略。響應體和 SSE 上服務端發給客戶端的 MCP 訊息會被轉發,目前不做策略解析。一批請求裡有一條被拒絕,整批拒絕。

策略按工具名寫,引數另開一道門

文件給的是 YAML,用 openshell policy set 整份寫入。增量的 policy update --add-endpoint 還不接受 mcp。下面是同一組欄位的 JSON,方便 Diff。查單放行,退款拒絕。預設 mcp.allow_all_known_mcp_methods 是 false,所以方法要一條條寫。省略 mcp.versions 時,只允許 2025-11-25 這個修訂:

{
  "version": 1,
  "network_policies": {
    "orders": {
      "name": "orders",
      "endpoints": [{
        "host": "orders.example.com",
        "port": 443,
        "path": "/mcp",
        "protocol": "mcp",
        "enforcement": "enforce",
        "mcp": {
          "strict_tool_names": true,
          "max_body_bytes": 65536
        },
        "rules": [
          { "allow": { "method": "initialize" } },
          { "allow": { "method": "notifications/initialized" } },
          { "allow": { "method": "tools/list" } },
          { "allow": { "method": "tools/call", "tool": "lookup_order" } }
        ],
        "deny_rules": [
          { "method": "tools/call", "tool": "refund_order" }
        ]
      }],
      "binaries": [{ "path": "/usr/bin/python3" }]
    }
  }
}

filesystem_policy 和 landlock 在沙箱建立時鎖死。network_policies 可以熱載入。二進位路徑要寫上,策略是「哪個程式可以打到哪個端點」。出站預設不放行私網,也不授權迴環、鏈路本地和雲後設資料地址。允許 lookup_order 之後,引數門在宿主:

{
  "type": "object",
  "properties": {
    "order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
  },
  "required": ["order_id"],
  "additionalProperties": false
}

這道 Schema 不是 OpenShell 的欄位。代理放行工具名之後,宿主仍要拒絕缺欄位、多欄位和不合 A-1042 形狀的引數。Schema 為什麼是門,見 AI 為什麼需要 JSON Schema。

四道門不要合成一道

名字都叫安全。擋住的物件不一樣:

門 它看什麼
OpenShell 代理 沙箱到 orders.example.com:443/mcp 的請求。方法、工具名、呼叫它的二進位。不看 arguments。
宿主 Schema lookup_order 的引數。型別、必填、pattern。過了門才執行。
Coding Agent 的 allow / ask / deny 會話裡的 Shell、Git、檔案工具。那是 harness 的名單。OpenShell 是沙箱外的另一層。
Sentry BlueField-4 上的帶外執行。越界就隔離。公開材料沒有給出一份 Sentry 的 JSON 欄位表,不要用本篇的策略物件冒充它。

策略改動在生效前還可以過 prover。它標出新的帶憑據可達、新的 HTTP 方法、對雲後設資料的訪問。有發現就不自動批准。命令列工具是 openshell-prover,可以放進 CI。Agent 只能經 Policy Advisor 提交窄提案,批准發生在沙箱外面。環和狀態怎麼落,見 Agent Harness 與 JSON State。

六步再放寬一條規則

不要從「先開 Sentry」開始。先寫清哪一次呼叫被哪一層擋住:

  1. 把模型 JSON 和執行時策略分開。模型填 params.name。OpenShell 決定這個名字能不能離開沙箱。
  2. 建立沙箱時寫好檔案系統和 Landlock。這兩段之後不能當網路規則熱載入。
  3. MCP 端點寫全。host、port、path: /mcp、protocol: mcp、enforcement: enforce。不要和別的協議共用同一主機和埠。
  4. 工具名一條條寫。initialize、notifications/initialized、tools/list,再加 tools/call 加 lookup_order。refund_order 放進 deny_rules。strict_tool_names 保持 true。
  5. 引數交給宿主 Schema。代理不讀 order_id。退款如果被塞進一個已允許工具的引數裡,這層不會看見。
  6. 放寬之前做 Diff,並用 prover。Sentry 是 BlueField-4 上的可選層。沒有這塊 DPU,不要把隔離寫成已經發生。

一批 JSON-RPC 裡只要有一條被拒絕,整批被拒絕。查單不要和退款打在同一個批裡試探。服務端響應不在這條策略裡。

放寬規則前攤開三份物件

一次被拒,先分清是工具名、二進位路徑、主機埠,還是引數形狀。

  • 把 tools/call 和策略 格式化,再用 Schema 校驗 看 arguments 是否過門。
  • 用 JSONPath 提取 抽出 $.params.name、$.method、$.arguments.order_id。
  • 用 JSON Diff 對比放寬前後的 network_policies。先看多出來的 tool,再改提示。
  • 沙箱日誌看被拒的 host、path 和 binary。openshell logs --tail --source sandbox。
  • 日誌裡的令牌先 脫敏。訂單和金鑰不要貼進公共格式化站。JSONSort 在瀏覽器本地跑。

三份物件對得上,才算知道是哪一層擋住了 refund_order。Sentry 的隔離記錄不在這三份 JSON 裡。

常見誤區

  • 把 OpenShell 當成會話裡的 allow / ask / deny。那是 harness 的名單。OpenShell 是沙箱代理和核心。兩份策略都要在。
  • 以為允許了工具名就驗過了 order_id。文件寫明引數匹配尚未支援。宿主 Schema 不能省。
  • 只檢查模型回覆。代理看的是發往 MCP 端點的請求體。響應和 SSE 目前不解析。
  • 讓沙箱自己批准策略。Policy Advisor 只提交提案。批准在沙箱外。prover 有發現就不自動批准。
  • 把 Sentry 寫成一份 JSON Schema。公開材料寫的是 BlueField-4 上的帶外隔離和關聯記錄。沒有線級欄位表,就不要編。
  • 用本篇重寫越獄事件。那些事件站內已經寫過。這裡只寫邊界怎麼擋一次 tools/call。

FAQ

Sentry 能代替 OpenShell 嗎?

不能。OpenShell 是軟體執行時,管沙箱、核心和出站策略。Sentry 是 BlueField-4 上的可選帶外層,越界時在毫秒級隔離。沒有這塊 DPU,就只有 OpenShell 那一層。兩層都在模型外面。

代理會讀 tools/call 的引數嗎?

不會。它匹配方法和工具名。允許的工具接受任意引數。一批請求裡有一條被拒絕,整批拒絕。引數形狀由宿主的 Schema 再驗一遍。

這和 Cursor、Claude Code 的權限檔案是一回事嗎?

不是。那些檔案決定會話裡的 Shell、Git 和檔案工具能不能跑。OpenShell 決定沙箱裡的哪個二進位能不能對哪個主機埠發出 MCP 請求。一個在 harness 裡,一個在沙箱邊界上。

prover 擋住的是什麼?

它在策略生效前做形式化檢查。新的帶憑據可達、新的 HTTP 方法、對雲後設資料的訪問會被標出,有發現就不自動批准。它不代替執行時的工具名規則,也不代替 Schema。

服務端的 MCP 響應也會被策略過濾嗎?

按當前文件,不會。JSON-RPC 響應,以及響應體或 SSE 上服務端發給客戶端的 MCP 訊息,會被轉發,不做策略解析。你要核的是離開沙箱的那份請求。

結論

NVIDIA 這套平台把工具呼叫的邊界放到模型外面。OpenShell 按 MCP 的工具名放行或拒絕。Sentry 在 BlueField-4 上把越界執行隔離開。引數仍由宿主用 Schema 驗。

先寫清 lookup_order 在 rules 裡,refund_order 在 deny_rules 裡,A-1042 在宿主 Schema 裡。三處對得上,這次呼叫才算被限制住。

延伸閱讀

更新記錄: 首次發布