我让一个 AI 编程代理帮我管理一台个人服务器:它有 shell,我的账号能读写的它都能读写,也能访问任意 URL。在处理一件与 SSH 无关的任务时,它打开了 ~/.ssh/id_rsa。没有报错,也没有越权:按我给它的权限,这次读取完全合法,它也没有用密钥做任何事。问题恰恰在这里:一切都在权限之内。它为什么能读这个文件?在我碰巧看到之前,它还读过什么?这两个问题我都答不上来。
这不是一个新问题。给一个进程超出任务所需的权限,又无法审计它用多出来的权限做了什么——sudo、SELinux 和安全工程里的每一套最小权限机制,针对的都是这个问题。新的只是进程的形态:一个自己决定下一步做什么的代理。我没有找到能把这套办法用在这种进程上的现成工具,于是开始写 AgentGuard。
三种失效方式
带工具的代理,即能读文件、执行命令、抓取网页的代理,值得关注的失效方式有三种。它们常被统称为「AI 安全」问题,但成因不同,对策也不同。
- 越界。任务只需要一个配置文件,它把上两层目录里的另一个也读了;
ls .足够,它执行了find /。没有恶意,只是没有任何机制阻止它。 - 被指挥。网页、文件、API 响应里都可能出现看起来像指令的文本。代理如果区分不了「正在处理的内容」和「应当执行的指令」,一份被投毒的文档就能改变它的行为。这是提示词注入。它与越界不同:代理没有越权,它执行了混在自己工具输出里的指令。
- 合法调用仍然泄密。代理被允许读那个文件,文件里恰好有一个 API 密钥。调用本身没有问题,问题在内容:没有任何机制在密钥进入上下文窗口之前把它遮住,而上下文之后可能被记录、被截屏、被传给另一个系统。
三种失效对应三套彼此独立的机制。这是 AgentGuard 最早定下的设计决定:它不是一个过滤器,而是三层。让一个机制同时做三件事,三件都做不好。
边界放在哪一层
机制定了,还要定执行的位置。候选位置有四个,前三个各有一个具体的不足。
- 写进提示词。「请不要读 SSH 密钥」是一句请求,不是边界。能被说服放弃的东西起不到边界的作用。
- 写进 MCP 服务器。自己写的服务器可以内置策略,但同一套规则要在用到的每个服务器里重写一遍;对拿不到源码的第三方服务器完全无效。
- 交给操作系统。容器、seccomp、受限用户都有用,和下面的做法也互补,但它们看到的是系统调用,不是一次工具调用的含义。操作系统能拦下「这个进程打开这个文件」,但不知道「这条 JSON-RPC 是一次调用
read_file的tools/call,参数里有一个形似路径的值」。我想在后一层写策略。
剩下的位置是协议层,在 AI 代理与 MCP 服务器之间。每条 tools/call 在转发前检查,每条结果在返回前检查。MCP 的 stdio 传输适合这么做:按行分隔的 JSON-RPC,两端都不用改。把代理的客户端配置指向 AgentGuard 而不是服务器,策略就在中间执行;两侧照常使用 MCP,不需要知道中间有它。
每条消息经过什么
- 请求侧的策略引擎。文件路径用 glob 拒绝列表,shell 命令用正则拒绝列表,网络调用用主机名允许列表。MCP 服务器之间没有统一的参数格式,规则按键名识别参数:
path、command、url等。被拒绝的调用不会到达服务器。这一层针对越界。键名是约定,不是保证:把路径放在其他键名下的服务器,这条规则识别不到。 - 响应侧第一遍:注入检测器。扫描工具输出里形似指令的文本。一旦命中,拦下整条结果,而不是删掉命中的句子;原因在下一篇展开。这一层针对被指挥。
- 响应侧第二遍:秘密脱敏器。对检测器放行的内容,再遮盖一遍已知格式的秘密。这一层针对泄密:调用没有问题,内容有问题。
(2026 年 9 月补记:以上说的是 0.1。从 0.2.0 起,参数属于哪一类,由服务器在 tools/list 里声明的 schema 和参数名里的词决定,例如 file_location 里的 file。两种途径都识别不出的参数默认仍然放行,在审计日志里记为 unclassified;把 unclassified_arguments 设为 deny 后,这样的调用会被拒绝。)
三层的每个决定都写入审计日志。日志是哈希链:每条记录包含前一条的哈希,过去的某一行被改动,重新校验一遍链就会暴露。链存在的原因是:一份改写后无法被发现的日志起不到审计的作用。
它不承诺什么
完整论证在仓库的威胁模型文档里,这里只写结论。我宁可发布一个范围窄、边界写清楚的工具,也不发布一个范围大、承诺兑现不了的工具。AgentGuard 不给 MCP 服务器进程加沙箱:服务器在操作系统层面做了什么,协议层的代理看不到。它不保证捕获所有注入措辞:规则公开在策略 YAML 里,读过的人可以绕开;计划中用于补这个缺口的 LLM 分类层尚未实现,这个缺口写在文档里。审计日志能发现篡改,不能阻止篡改:它能证明某一行被改过,但阻止不了有完整文件系统权限的人删掉整个文件、重新伪造一条自洽的链。
安全工具只有在使用者能确切知道它提供什么的时候才有用。夸大承诺的工具比没有更糟:它让人放弃了本来会自己做的核对。
这些结论写在 README 里,写在单独的威胁模型文档里,也写在这里。
下一篇只讲注入检测这一层:第一版为什么用规则而不是分类器,误报和漏报各自的代价,以及默认规则里一个真实发布出去、后来被测试套件发现的漏洞。