核心摘要

AI Agent 工具代表可执行权限,不是普通提示词扩展。生产系统应使用已验证注册表、最小权限、确定性授权、隔离执行、有界输入输出、精确操作审批和版本化审计。工具描述与结果都应视为不可信;模型拒答和系统提示词不能替代运行时策略。

Agent 工具调用中的信任边界

Agent 系统由两个控制面组成:

  • 模型根据自然语言上下文提出要做什么;
  • 可信软件判断是否允许并执行操作。

把“模型提议”误当成“已授权操作”,安全边界就会失效。

flowchart LR A["用户与不可信内容"] --> B["模型规划器"] C["已审查工具注册表"] --> B B --> D["候选工具与参数"] D --> E["策略与审批"] E --> F["沙箱执行器"] F --> G["外部系统"] G --> H["有界不可信结果"] H --> B

每条箭头都是信任边界。用户输入、检索文档、工具描述、调用参数、远程响应、记忆和委派 Agent 消息都可能改变下一步决策。

威胁模型:四条不同攻击路径

不要把所有事故都归为“提示词注入”。不同路径需要不同控制。

攻击路径 示例 主要控制
直接或间接提示词注入 网页要求 Agent 上传私有文件 能力限制、来源标记、出口策略
工具投毒 工具描述隐藏指令,或审查后改变行为 注册表验证、版本锁定、差异审查
函数调用后的工具滥用 Agent 用合法删除 API 操作了错误资源 对象授权、预览、审批、幂等
恶意工具结果 返回内容含指令、秘密或超大负载 结果 Schema、大小限制、污点标记、内容隔离

OWASP Agentic Skills Top 10 强调发布者验证、权限清单、安全解析、依赖锁定、沙箱与运行时监控。本质上是把成熟软件供应链控制应用到由模型引导的执行层。

建立已审查工具注册表

动态发现不代表动态信任。发现的工具应转换为目标环境中经过审查的内部注册表条目。

json
{
  "tool_id": "invoice.lookup",
  "version": "3.2.1",
  "artifact_digest": "sha256:...",
  "publisher": "billing-platform",
  "effects": ["read:invoice"],
  "network_allowlist": ["billing.internal"],
  "data_classes": ["customer_financial"],
  "approval": "none",
  "result_max_bytes": 65536
}

以下实质变化都要触发新一轮审查:

  • 名称或描述;
  • 参数或结果 Schema;
  • 请求权限;
  • 网络目标;
  • 软件依赖或制品摘要;
  • 副作用行为;
  • 数据保留规则。

MCP Server、插件、Skill 或软件包注册表只是“不可信候选来源”,内部注册表才是执行授权来源。

在运行时执行最小权限

权限必须比“Agent 可以调用该工具”更细。系统应根据可信身份和当前状态授权精确副作用。

typescript
type ToolRequest = {
  tool: "invoice.lookup" | "invoice.refund";
  invoiceId: string;
  amount?: number;
};

async function authorize(
  request: ToolRequest,
  context: { userId: string; tenantId: string; roles: string[] },
) {
  const invoice = await loadInvoice(request.invoiceId);
  if (invoice.tenantId !== context.tenantId) throw new Error("tenant_denied");

  if (request.tool === "invoice.refund") {
    if (!context.roles.includes("refund_operator")) throw new Error("role_denied");
    if (!request.amount || request.amount > invoice.refundableAmount) {
      throw new Error("invalid_amount");
    }
  }
  return invoice;
}

模型不能提供 userIdtenantId、角色、价格、审批状态或策略版本。这些字段应从认证上下文与权威服务派生。

同时设置资源预算:

  • 最大工具调用数与重复调用次数;
  • 执行时间和并发;
  • 输出字节数和行数;
  • 网络目标与请求方法;
  • 文件系统路径与进程能力;
  • 金额、写入量和重试次数。

让审批真正约束操作

只显示“是否允许?”不构成有效审批。用户需要看到精确副作用:

text
为发票 inv_2817 退款 ¥612.40
目标:原支付方式
原因:重复扣款
工具版本:[email protected]
过期时间:2026-07-28T12:05:00Z

审批应绑定到:

  • 工具及版本;
  • 规范化参数;
  • 目标资源和租户;
  • 目标地址与副作用;
  • 策略版本;
  • 过期时间与幂等键。

任一绑定字段变化都要重新审批,不能让一次确认授权后续更宽的调用。

把工具结果视为不可信输入

工具调用成功不代表返回内容安全。结果重新进入模型上下文前必须规范化。

typescript
function normalizeSearchResult(value: unknown) {
  if (!value || typeof value !== "object") throw new Error("invalid_result");
  const input = value as Record<string, unknown>;
  const text = typeof input.text === "string" ? input.text.slice(0, 8_000) : "";
  return {
    sourceId: String(input.sourceId ?? ""),
    text,
    trust: "external_untrusted",
  };
}

来源身份和信任标签应穿透摘要与记忆写入。返回文本不能直接定义新工具、改变策略、选择外部目标地址或写入持久记忆,除非通过单独门禁。

沙箱与网络出口限制

当授权或模型行为失败时,隔离可以限制影响范围。

边界 最低控制
进程 非 root 身份、系统调用与资源限制
文件系统 只读基础层、显式可写目录
网络 默认拒绝、目标和协议允许列表
凭据 短期、工具专用、租户范围
数据 最少字段、脱敏、结果大小上限
副作用 幂等键、预览、交易额度

读工具与写工具应分开。如果可以提供狭窄业务操作,就不要暴露通用 Shell、SQL 执行器、HTTP Client 或云凭据。

测试完整攻击链

安全测试要覆盖调用轨迹,而不只是单轮提示词:

  1. 被投毒的工具描述要求执行未声明前置操作;
  2. 搜索结果要求外传数据;
  3. 工具返回其他租户标识符;
  4. 超时后模型重复写操作;
  5. 规划与执行之间工具版本变化;
  6. 委派 Agent 请求更宽凭据;
  7. 输出尝试把指令写入长期记忆。

每个案例都要断言阻止影响的确定性边界。模型“通常会拒绝”不能算安全测试通过。

遥测记录工具 ID 和版本、注册表摘要、认证主体、策略决策、审批引用、规范化参数摘要、目标类别、副作用结果、耗时和有界错误码。不要保存原始秘密、完整提示词和全部私有返回值。

事故响应与熔断

事故前就要准备:

  • 全局禁用某个工具版本或发布者;
  • 独立撤销工具凭据;
  • 阻断某个目标地址或副作用类型;
  • 隔离受影响执行写入的记忆;
  • 按制品摘要定位历史调用;
  • 使用脱敏 Fixture 重放策略决策;
  • 通知外部可见副作用的责任人。

审计日志既要有调查价值,也不能变成第二套敏感数据仓库。低敏关联元数据与严格受控的负载证据应分开存储。

生产检查清单

  1. 盘点工具、效果、数据类别和外部目标。
  2. 把发现结果转换为已审查允许列表。
  3. 锁定制品并审查每次实质更新。
  4. 从可信上下文派生身份与租户。
  5. 用代码校验并授权精确副作用。
  6. 沙箱执行,网络出口默认拒绝。
  7. 审批绑定精确参数与版本。
  8. 规范化、限制并标记每个工具结果。
  9. 测试注入、投毒、重试、委派和记忆持久化。
  10. 维护熔断开关和事故查询。

提示词注入防御指南覆盖更广泛的不可信内容问题;函数调用指南解释模型提议到实际执行的边界。

常见问题

可以允许 Agent 自行安装工具吗?

不能直接安装到生产信任域。Agent 可以发现候选或生成变更申请,但安装、权限、制品验证和启用需要独立审查流程。

已签名工具一定安全吗?

不一定。签名只能证明相对于某个密钥的来源与完整性,不能证明发布者可信、代码安全、权限最小或返回内容无害。

输入输出分类器能阻止工具攻击吗?

分类器可以提供信号,但具有概率性且可被绕过。它们可以参与策略或复核,不能成为保护数据与副作用的唯一屏障。

写工具应如何重试?

使用幂等键和权威状态查询。出现不明确超时时,先查询操作结果再决定是否重试,不能让模型自行判断写操作可以重复。

有人工审批就足够安全吗?

只有当用户看到准确、有界的操作,并且审批与该精确操作绑定时才有效。模糊或过载的确认会导致审批疲劳,也不会真正收窄权限。

参考资料