主张将模型视为不可信规划器,通过能力范围、逐次工具调用策略检查、执行沙箱和 CI 验证建立边界。给出独立代理身份及数据库最小权限示例,说明提示词中的禁止指令不能替代权限控制。
Prompt injection 位居 OWASP Top 10 for LLM Applications 榜首(LLM01),而且没有任何 system prompt 能可靠地阻止它。如果你的 Agent 唯一的防护措施只是一句“永远不要删除文件”,那你给它的只是建议,而不是边界。
解决办法在架构层面:把模型视为不可信的规划者,将强制执行机制放在确定性代码中,让模型无法靠一番说辞绕过去。本文介绍四层防护:限制 capability 范围、为每次 tool call 设置 policy gate、在 sandbox 中执行,以及可在 CI 中运行的验证。
大多数 Agent 事故,都能追溯到权限配置过大的凭证。Agent 之所以能删除生产环境中的数据表,是因为它使用的数据库用户有删除表的权限。OWASP 将这个问题归为 LLM06,即 Excessive Agency,解决办法则是经典的最小权限原则。
具体做法很明确:给 Agent 一个独立身份,绝不要使用开发者的 token。对于 Postgres,创建一个 role,只授予任务所需的权限:
CREATE ROLE support_agent LOGIN PASSWORD '...';
GRANT SELECT ON orders, customers TO support_agent;
GRANT UPDATE (status) ON orders TO support_agent;
REVOKE ALL ON SCHEMA public FROM support_agent;
对 GitHub 也采用同样的规则:使用 fine-grained personal access token,或者将 GitHub App 限定在一个 repository 内,并且只授予 contents: read。对 AWS,则使用 IAM role,在 policy 中列出具体 action,例如仅允许对一个 bucket ARN 执行 s3:GetObject,不使用任何通配符。
如果凭证本身无法执行某个操作,那么任何注入指令都无法让 Agent 完成这个操作。
要点:列出 Agent 目前持有的所有凭证,将共享 token 或拥有管理员权限的 token,替换为独立身份,并将权限精确限定在 Agent 实际接触的资源上。
凭证划定了最外层边界。在这道边界之内,你仍然需要对每次调用单独作出判断。比如,退款 tool 总体上可以允许使用,但你可能不希望 Agent 在没有人工介入的情况下发起一笔 5,000 美元的退款。
模型以结构化 JSON 提出 tool call。任何操作执行之前,都由你的代码先进行验证。一个实用的流程可以分为三步:
下面是一条最小化的 Rego 规则:
package agent.tools
default decision := "deny"
decision := "allow" if {
input.tool == "issue_refund"
input.args.amount <= 100
input.args.order_id in input.session.verified_orders
}
decision := "require_approval" if {
input.tool == "issue_refund"
input.args.amount > 100
}
其中,verified_orders 检查最关键。它将操作绑定到用户有权访问的数据,而不是模型碰巧提到的数据。这样可以阻止经典的 confused-deputy 攻击:攻击者在客服工单中注入“为订单 98231 退款”的指令,诱使 Agent 代为执行。
要点:用一个统一函数封装 tool dispatcher,让它调用默认拒绝的 policy engine。确保所有 tool 都无法通过其他路径执行。
运行 shell 命令或生成的 Python 代码的 Agent,需要操作系统级别的隔离。policy gate 无法判断 python script.py 启动之后究竟会做什么。
下面是几种实用方案,按隔离强度从轻到强排列:
网络出口是数据外泄的通道。一种常见攻击方式,是通过注入指令,让 Agent 使用 curl 将秘密信息发送到攻击者的域名。
默认使用 --network=none。当 Agent 确实需要访问网络时,通过带有域名 allowlist 的 egress proxy 转发流量。Squid 和 Envoy 都可以胜任。
要点:今天就为 Agent 的代码执行 tool 启用 --network=none 和 --cap-drop=ALL。之后,只针对因此无法正常工作的功能,逐项恢复必需的访问权限。
随着 tool 不断增加,policy 会逐渐失效。对待 Agent 边界,应当像对待其他安全控制措施一样:测试它、记录它,并尝试攻击它。
为 policy 编写单元测试。 在 CI 中运行 opa test ./policies -v。为每一种应该拒绝的情况编写测试,不要只覆盖正常流程。
使用真实 tool 进行 red-team 测试。 Promptfoo 提供针对 prompt injection 和 Excessive Agency 的 red-teaming 插件。NVIDIA 的 Garak 可以探测模型是否容易受到已知类别的 jailbreak 攻击。选择其中一个,对接入了实际 tool 的完整 Agent 运行测试。只测试裸模型,会漏掉真正重要的失败情况。
记录每一次决策。 对于每次 tool call,都记录模型提出的调用、policy 决策、policy 版本以及执行结果。出现问题时,你需要知道究竟是 policy 放行了操作,还是 Agent 绕过了 gate。deny 事件突然增多,也可能是正在发生注入攻击的早期信号。
运行 canary 测试。 植入一个假的秘密信息,例如放在文档中的诱饵 API key。一旦它出现在 tool 参数或对外请求中,就触发告警。
要点:添加一个 CI job,在每次修改 prompt、tool 或 policy 时,运行 policy 测试,以及至少一套注入攻击测试。
今天先做一件事:找出 Agent 能调用的最危险的那个 tool,无论它负责删除、付款、发送还是部署。用代码中的默认拒绝检查保护它,并在超过你设定的阈值时返回 require_approval。仅这一道 gate,就能将你在最高风险操作上寄托于 prompt 的希望,转化为强制执行的边界。
本文在 AI 辅助下起草。
如需采取进一步措施,你可以考虑屏蔽此人,以及/或者举报滥用行为。