测试只在构建时运行一次,Guardrail在每次真实请求时执行;AI Agent要安全投产,两者缺一不可,扫描发现大量线上漏洞恰好出现在测试与生产之间的盲区。
一条评论精准地点明了核心观点
几天前,在 Humanbound 从事运行时护栏工作的评论者在我们的 AI Agent 安全审计帖子下留下了这样一段话:
"任何时候,当一个测试失败,它都会自动成为一个运行时护栏,这样同样的错误就不会再次漏过去。"
这一句话就是本文的主旨。大多数团队把"我们写了一套测试"当作"我们已经保护好了 Agent"。测试是一个在构建时运行的检查点,运行完就停止关注。护栏则是一条策略,当系统进入生产环境后依然在岗,持续检查实际到达的请求。两者之间的区别并非细微——它决定了检查发生在哪里,以及它会被执行多少次。
测试只运行一次。护栏每次都运行。
单元测试在受控环境中针对你选定的 fixture 执行。它失败了,你修复它,然后继续——下一次部署从同样的干净状态开始。这次失败在沙箱中给你上了一课,而且只有当测试恰好覆盖了那个确切输入时才会发生。
运行时验证在结构上就有所不同。检查在真实调用发生的时刻执行,在真实部署中,针对模型实际选择的请求和工具表面。同一条规则适用于第一次调用和第一万次调用。调用之间没有干净状态,因为下一次调用已经在路上了。
对于 AI Agent 来说,这种不对称性比大多数软件更重要。Agent 的行为不是一个固定的代码路径;它是模型与一组工具之间的协商,而模型在给定请求上伸手去拿的工具在构建时是无法完全预测的。你真正关心的失败模式是你无法在模型遇到它们之前枚举的——而这恰恰是预写测试无法保证覆盖的那一类。
为什么测试总是遗漏真正重要的失败
在我们的 MCP-based Agent 中不断出现的攻击,并不是你代码中的逻辑 bug——而是运行时配置的固有属性。一份 MCP 配置文件是可执行内容,而不是数据。一个恶意或意外配置错误的服务器可以被指示运行任意命令,而模型会忠实地将提示词所要求的一切交出去。
三个真实的、NVD 登记在案的例子说明了这种运行时表面:
CVE-2026-2287 — CrewAI 的 MCP stdio 传输,CVSS 9.8。一次无需验证即可调用命令的工具调用路径,导致远程代码执行。
CVE-2026-42271 — LiteLLM,CVSS 8.7(旧评分体系下为 8.8)。通过 MCP 测试端点执行命令;已被列入 CISA 的 KEV 清单,标记为正在被积极利用。
CVE-2026-12957 — Amazon Q Developer,CVSS 8.5。一个恶意的 .amazonq/mcp.json 在加载时自动执行,并能窃取云凭证。
测试套件无法在你的 Agent 内部捕获这些问题,因为它们根本不在你的 Agent 内部。它们在 Agent 与其调用的工具之间的契约里——而这份契约只在运行时、在真实请求到达的那一刻才存在。
我们的扫描在 12 个框架中发现了什么
我们在 12 个主流 AI 框架上运行了 Correctover CCS v4.2 扫描器,记录了 87 个漏洞。最常见的漏洞不是任何一个框架自身业务逻辑中的 bug;而是一个协议层面的缺口:MCP 的 readOnlyHint 信号有定义但从未被强制执行,所以声明为只读的工具仍然可以被调用来执行写操作。下游框架从它们构建的 SDK 中继承了这个缺口。
这一发现很好地印证了测试与护栏之间的差距。检查在规范中有定义。一条检查你自己代码的测试会通过。只有站在工具调用边界上、对实际调用进行评估的运行时检查才能观察到违规——因为违规只存在于调用发生的那一刻。
护栏必须足够快,快到让人无感知
如果护栏成了拖慢 Agent 的东西,这一切就毫无意义。CCS 验证器的评估路径在 50,000 次迭代每场景的测量下,中位数延迟低于 10µs,第 99 百分位低于 25µs。在这个成本下,每次调用都运行检查并不是你需要权衡的取舍。
"在运行时"实际上构建在什么之上
护栏的好坏取决于它背后的失败目录。我们的分类法不是一个预先写好的静态列表;而是从真实流量中生长出来的。我们从 13 个 LLM 提供商的真实调用中收集了超过 80,000 条 API 追踪——其中 20,000 条追踪子集已随 CCS 基准数据集发布——而且仅 CCS v4.2 扫描语料库就包含超过 1,730 个已验证的发现。
我们遵循的规则正是那位评论者所描述的:只有当一个失败能够从可审计的追踪中重新推导出来之后,它才能获得一个永久条目;随着提供商在上游改变行为,新的形态持续进入目录。这是一个有意为之的滞后策略,我们对这种权衡保持开放——一个停止被重新检查的分类法会重新退化为理论。
护栏就是产品
我们正式确立了这个立场,因为我们相信运行时验证是一门独立的工程学科,而不是测试的一个变种。我们在 IETF 上发布的草案(draft-correctover-ccs-02)定义了一个 Agent 如何产生关于每次调用上运行了哪些检查的防篡改证据——这是测试无法产生的证据,因为测试在调用发生时根本不存在。
这就是 CCS 项目用一行话的定义:一个运行时验证器,在关键时刻检查工具调用和响应,成本足够低廉,可以每次调用都运行。扫描器作为按次付费检查提供(¥0.7/次,¥7 捆绑包包含 10 次),同一验证层也作为 MCP 工具暴露,使 Agent 可以在链中途自我检查,而不仅仅在末尾。如果你正在 MCP 服务器之上构建 Agent,最小的有用实验是用扫描器跑一下你已经信任的服务器——看看运行时检查发现了什么你的测试套件没有发现的东西。