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 里。三处对得上,这次调用才算被限制住。

延伸阅读

更新记录: 首次发布