跳到主要内容

工具组合提权:你的安全审查清理了节点,而非边缘

· 阅读需 12 分钟
Tian Pan
Software Engineer

read_file 是安全的。send_email 是安全的。你的安全审计对照各自的威胁模型分别批准了它们:对已知目录的只读访问,以及通过带有速率限制和收件人日志记录的已认证中继发送的出站邮件。每一个都通过了,两者都已注册。随后智能体将它们组合在一起,而客服工单中的一行注入文本就将这对组合变成了外泄工具,原有的审计对此根本没有描述这种风险的术语。

危险并不存在于工具图谱的任何节点中,而是在于边。你运行的每次针对单个工具的安全审计都是对顶点的判定;而智能体实际的权限表面是目录中的路径集合,这个集合呈二次方增长,而你的审计流程却只能线性扩展。当你的智能体拥有 15 个注册工具时,你审计了 15 个项,却发布了大约 200 个可达的两步组合,其中没有一个经过人工审核。

这是在规划器(planner)层面重建的混淆代理(confused-deputy)问题。智能体拥有合法的凭证,用户拥有合法的意图,每一次工具调用都符合策略,但系统仍然发生了泄露。云安全联盟(Cloud Security Alliance)在 2026 年的一份研究报告中准确定义了这一类别:智能体拥有合法的权限,决策受到对抗性输入的影响,由此产生的操作虽然在每个工具'的策略范围内,但却超出了对用户意图的任何合理解释。策略在每个节点都得到了满足,但在执行轨迹上被违反了。

无人列举的组合图谱

走一遍你的智能体实际提供的权限集,而不是你的注册表所列出的那个。

一个拥有 fetch_urlread_repo_fileopen_pull_request 的编程助手看起来像是具备了三个合理的技能。将它们组合起来,你就得到了一个已被记录的攻击模式:攻击者在公共 GitHub issue 中植入指令,智能体在常规上下文收集过程中抓取该 issue,注入的文本指示智能体读取包含 API 密钥的同级文件,然后智能体开启一个 PR,其正文包含窃取的密钥。每一步都使用了授权的工具针对授权的目标。这种组合本身就是漏洞利用。Invariant Labs 在 2025 年针对一款流行的编程智能体展示了正是这种模式;数据外泄通道是一个公开的 PR 正文,而 open_pull_request 的安全审计曾将其视为对低敏感度表面的写入。

一个拥有 read_ticketquery_accountsend_message 的客服智能体看起来像是最小可行工具集。将它们组合起来,ForcedLeak 类攻击就会出现:注入内容存在于智能体作为合法上下文读取的 CRM 字段中,该注入重定向规划器去查询用户并未要求的账户数据,智能体通过安全部门为其他目的批准的白名单聊天连接器发送数据。外泄通道就是产品功能本身。

2025 年事故语料库中最常被提及的危险组合是 exec_codehttp_request。它们加在一起涵盖了读取、转换和发送。单独任何一个都是受控风险;合在一起它们就是一个不受限制的出站通道,而你的网络团队几乎肯定认为这个通道不存在。2026 年的一项关于智能体权限提升的审查指出,这对组合在一次又一次的部署中出现,因为每个工具都独立地解决了一个真实的产品问题,而且没有任何一个审计人员有权说“你可以拥有其中一个,但不能同时拥有两者”。

架构上的认识是令人不安的:你的工具目录不是一个权限集。它是权限集的生成器。安全团队审计了生成器;而智能体运行的是生成的集合。这两者是不同的对象。

安全团队从未审计过的组合图谱

这里失效的思维模型是继承自 Web 应用安全的模型,即每个端点是一个节点,授权发生在节点上。在这种模型中,保护系统意味着保护端点;如果每个端点都是正确的,那么系统就是正确的。组合表面很小,因为客户端不是自主的,不会基于对抗性输入来链接调用。

智能体反转了这一点。规划器是客户端,规划器的一部分指令来自流经工具层的不可信输入,而调用链是由一个实体在运行时构建的,任何控制了智能体最终会读取的字符串的人都可以引导该实体的选择。针对固定威胁模型对每个工具进行的静态审计无法捕获组合漏洞,因为组合所违反的威胁模型并不存在于任何单个工具的审计中。

更糟的是,你的审计日志是错误的。大多数智能体平台在调用边界进行记录:工具名称、参数、返回值、延迟、错误。审计人员阅读日志时看到的是一系列已通过的调用。他们需要的信息——即第三次调用的参数源自第一次调用的不可信输出,且该链条整体上将数据从私有表面移动到了公开表面——在调用边界是不可见的,因为没有人持久化数据流的边。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates