NVIDIA 發布 AI Agent 安全平台:OpenShell、Sentry 如何限制 Agent 的 JSON Tool Calls?
模型仍然只填 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」開始。先寫清哪一次呼叫被哪一層擋住:
- 把模型 JSON 和執行時策略分開。模型填
params.name。OpenShell 決定這個名字能不能離開沙箱。 - 建立沙箱時寫好檔案系統和 Landlock。這兩段之後不能當網路規則熱載入。
- MCP 端點寫全。
host、port、path: /mcp、protocol: mcp、enforcement: enforce。不要和別的協議共用同一主機和埠。 - 工具名一條條寫。
initialize、notifications/initialized、tools/list,再加tools/call加lookup_order。refund_order放進deny_rules。strict_tool_names保持 true。 - 引數交給宿主 Schema。代理不讀
order_id。退款如果被塞進一個已允許工具的引數裡,這層不會看見。 - 放寬之前做 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 裡。三處對得上,這次呼叫才算被限制住。
延伸閱讀
- Coding Agent 的權限模型 allow / ask / deny,和沙箱不是同一層
- Coding Agent 如何呼叫 MCP tools/call 的 JSON-RPC 形狀
- Agent 安全危機與 JSON 驗證 事件已經寫過,本篇不重寫
- Agent Harness 與 JSON State 環、門、狀態
- 為什麼 AI 需要 JSON Schema Schema 是門
- JSONSort 本地工具箱 格式化、校驗、Diff、Schema
- 全部文章 更多 JSON 與 AI 開發筆記
更新記錄: 首次發布