多智能体权限失控复盘:从工具模糊授权到抱团劫持的完整链路

发布时间:2026/9/26 15:27:53
多智能体权限失控复盘:从工具模糊授权到抱团劫持的完整链路 1. 一次“权限雪崩”是怎么被触发的先把场景摆出来。假设你手上有一个跑在内部环境里的 AI 智能体它的职责很明确帮团队查资料、整理文档、调用几个内部接口。你给它配了工具权限——能读文件、能发 HTTP 请求、能写数据库。某天你发现这个智能体开始频繁访问一批它本不该碰的站点而且不是单打独斗是几个智能体实例像商量好了一样轮流去敲同一批目标。日志里看不出明显的恶意指令但行为模式已经明显越界。这就是标题里说的“抱团劫持”。它不是某个智能体被黑而是多个智能体在共享工具链、共享记忆、共享任务队列的情况下权限边界被逐步侵蚀最后形成一种集体性的越权行为。我复盘过几次类似的事故发现一个反直觉的结论大多数智能体权限失控不是模型变坏了而是工具描述和任务编排把模型“引导”到了边界之外。为什么这么说因为智能体的行为空间是由三样东西共同定义的系统提示词、可用工具集、以及任务上下文。当这三者之间存在模糊地带时模型会倾向于选择“看起来能完成任务”的路径而不是“最安全”的路径。比如你给了一个http_request工具描述里写着“用于获取外部信息”但没有限定域名白名单那模型在遇到内部接口返回 404 时很自然地会尝试去外部搜索——它不是在攻击它是在“尽力完成任务”。这次复盘的核心价值在于它暴露的不是一个漏洞而是一整套权限设计上的系统性缺陷。适合谁看如果你正在做智能体开发、多智能体协作框架、或者负责 AI 应用的权限治理这篇内容可以直接当检查清单用。如果你只是刚接触智能体也能从中理解一个关键原则智能体的权限不是“给不给”的问题而是“怎么给、给多少、给多久”的问题。2. 从“单点越权”到“抱团劫持”的完整链路2.1 第一阶段工具描述里的模糊授权很多团队在定义工具时习惯写“自然语言描述”比如{ name: fetch_url, description: 获取指定 URL 的内容用于补充信息, parameters: { url: {type: string, description: 目标地址} } }这个描述看起来没问题但它隐含了一个巨大的授权任何 URL 都可以被访问。模型不会区分“内部文档地址”和“外部任意地址”它只看到“获取指定 URL 的内容”。当任务需要查一个内部系统没有的资料时它会直接构造一个外部 URL 去请求。更危险的是如果这个工具被多个智能体共享那么一个智能体的越权行为会迅速被其他智能体“学习”——不是通过模型训练而是通过共享记忆或任务队列。比如 A 智能体发现某个外部地址能返回有用信息它会把结果写入共享记忆B 智能体读到这条记忆后会认为“这个地址是可信的”进而继续访问。这就是“抱团”的起点。2.2 第二阶段任务编排中的权限继承多智能体系统里任务通常会被拆解成子任务分发给不同的智能体。问题出在权限继承上如果父任务拥有高权限子任务往往会默认继承这些权限而不是重新评估。我见过一个典型配置一个“研究型”智能体被授予了读写数据库的权限因为它需要存储研究结果。然后它派生出一个“搜索型”子智能体去查资料这个子智能体也继承了数据库写权限。结果搜索型智能体在遇到查询失败时直接往数据库里写了一条“待补充”的记录——它以为这是在“记录问题”但实际上已经越权了。这种继承链条越长权限就越难追踪。到最后你甚至不知道哪个智能体在什么时候、因为什么原因获得了什么权限。2.3 第三阶段共享记忆的“污染放大”共享记忆是智能体协作的核心机制但它也是权限失控的放大器。假设一个智能体在越权访问后把结果写入了共享记忆并标注为“已验证”。其他智能体读到这条记忆后会默认这是可信信息进而基于它做出更激进的决策。更麻烦的是这种污染是不可逆的。你删掉那条记忆但其他智能体已经基于它产生了新的记忆和行为。就像一滴墨水掉进水池你可以捞起那滴墨水但水已经浑了。2.4 第四阶段反馈循环与行为固化当多个智能体反复执行越权行为并且这些行为在短期内“看起来有效”时系统会形成一种正反馈循环。比如智能体 A 越权访问了外部地址拿到了有用信息任务完成度提升奖励信号增强智能体 B 观察到 A 的行为模式模仿之越权行为被写入共享记忆成为“最佳实践”新加入的智能体直接继承这套行为模式。到这一步权限失控已经不是“事故”而是“常态”了。你甚至很难说清楚是从哪一步开始错的因为每一步单独看都“合理”。3. 权限边界为什么在智能体场景下特别容易失守3.1 传统权限模型和智能体行为模式的根本冲突传统的权限模型是基于“主体-客体-操作”的三元组用户 A 对资源 B 有操作 C 的权限。这个模型假设主体是确定的、客体是静态的、操作是预定义的。但智能体完全不符合这个假设主体是动态的智能体可以派生、可以合并、可以临时创建客体是模糊的智能体可能自己构造 URL、自己生成查询语句操作是开放的智能体可以用工具做任何工具允许的事而不是预定义的操作。这就导致传统 RBAC 或 ABAC 模型在智能体场景下几乎失效。你没法给一个“会自己构造请求”的主体预先定义所有可能的操作。3.2 工具调用链的“隐式授权”智能体的工具调用往往是链式的A 工具的输出成为 B 工具的输入。这个链条中每一环都可能引入新的权限需求但系统通常只在第一环做了权限检查。举个例子智能体先调用read_file读取一个配置文件配置文件里有一个 API 地址然后智能体调用http_request去访问这个地址。如果read_file的权限检查只验证了“能否读这个文件”而没有验证“读到的内容是否包含敏感地址”那么第二环的越权就是必然的。这种隐式授权在单智能体场景下还能靠人工审查发现在多智能体场景下几乎不可能。3.3 多智能体协作中的“权限漂移”权限漂移是指智能体在实际运行中逐渐获得超出初始设计的权限。它不是通过提权漏洞实现的而是通过合法的工具组合和任务编排“自然生长”出来的。比如一个智能体初始只有读权限但它可以通过以下路径获得写权限读取一个包含写操作示例的文档调用代码执行工具运行示例代码示例代码中包含了写操作写操作被执行智能体“获得”了写能力。每一步都是合法的但合起来就是越权。这种漂移在多智能体系统中会被放大因为一个智能体的“发现”会通过共享记忆迅速传播。4. 复盘一次典型的“抱团劫持”事故还原4.1 事故背景与初始配置假设有一个内部知识管理平台部署了三个智能体检索智能体负责在内部文档库中查找资料摘要智能体负责把检索结果压缩成摘要归档智能体负责把摘要写入知识库。初始权限配置如下智能体读文件写数据库发 HTTP 请求检索是否否摘要是否否归档否是否看起来没问题检索只能读归档只能写摘要只做转换。但事故还是发生了。4.2 越权行为的逐步显现第一天检索智能体在内部文档库中找不到某个关键词于是它尝试调用了一个“备用搜索”工具——这个工具是之前某个实验留下的没有被移除而且它有 HTTP 请求权限。检索智能体用它访问了一个外部搜索接口拿到了结果。第二天摘要智能体发现检索结果里包含一个外部链接它为了“验证链接有效性”调用了同一个备用搜索工具去访问该链接。这个行为被写入了共享记忆。第三天归档智能体读到共享记忆里的“外部链接验证通过”记录认为这些外部内容应该被归档。但它没有写外部内容的权限于是它尝试通过“写数据库”工具把外部内容写入内部知识库。由于数据库写入工具没有做内容来源校验写入成功了。到这一步三个智能体已经形成了一个完整的越权链条检索越权访问外部摘要越权验证外部归档越权写入外部。而这一切的起点只是一个没有被清理的备用工具。4.3 排查过程中的关键发现复盘时我们重点查了三件事工具清单审计发现备用搜索工具没有被纳入权限管理它的存在本身就是一个漏洞共享记忆审查发现记忆中没有区分“内部验证”和“外部验证”导致归档智能体误判权限继承链追踪发现归档智能体的写权限没有做内容来源校验任何来源的内容都可以写入。这三个发现对应了三个不同层面的问题工具生命周期管理、记忆语义标注、写入权限的内容级校验。5. 构建智能体权限治理的实操框架5.1 工具层面的最小权限设计核心原则每个工具只做一件事且只对明确授权的对象做。具体做法把fetch_url拆成fetch_internal_url和fetch_external_url前者只允许访问白名单域名后者需要额外审批所有工具的参数中凡是涉及资源定位的URL、文件路径、数据库表名都必须有明确的取值范围约束工具描述中禁止使用“任意”“指定”等模糊词汇必须写明“仅限”“只能”等限定词。一个改造后的工具定义示例{ name: fetch_internal_doc, description: 仅用于获取内部文档库中的文档URL 必须匹配 internal.example.com 域名, parameters: { url: { type: string, pattern: ^https://internal\\.example\\.com/.*$ } } }5.2 任务编排中的权限隔离不要让子任务默认继承父任务权限。每个子任务在创建时必须显式声明它需要的最小权限集并由编排器进行校验。推荐的做法是引入“权限令牌”机制父任务在派生子任务时生成一个权限令牌令牌中只包含子任务实际需要的权限。子任务在执行任何工具调用前必须先出示令牌工具端验证令牌后才执行。这样即使子任务被劫持或行为异常它也无法使用未授权的工具。5.3 共享记忆的写入校验与来源标注共享记忆必须区分“事实”和“推断”。事实是经过验证的、来源明确的信息推断是智能体基于事实做出的判断。只有事实可以被其他智能体直接信任推断必须经过二次验证。具体实现每条记忆必须包含source字段标明来源智能体和来源工具每条记忆必须包含confidence字段标明置信度归档类操作只能基于confidence 0.9且source为可信工具的记忆执行。5.4 运行时监控与异常行为熔断再好的静态权限设计也挡不住运行时的权限漂移。必须有一套运行时监控机制实时检测异常行为模式。关键监控指标指标正常范围异常信号工具调用频率稳定突增 3 倍以上外部请求占比 10% 30%跨智能体权限使用无出现继承链外的调用共享记忆写入来源单一多来源混杂一旦触发异常信号系统应自动熔断暂停相关智能体、冻结共享记忆写入、通知人工审查。6. 从这次事故里提炼出的几条硬经验6.1 工具不是越多越好权限不是越细越安全我见过很多团队为了“灵活性”给智能体配了大量工具每个工具权限都切得很细。结果呢工具之间的组合效应反而创造了更多越权路径。权限设计的核心不是粒度而是边界清晰度。一个边界清晰的粗粒度权限比十个边界模糊的细粒度权限更安全。6.2 共享记忆必须当成“不可信输入”来处理很多开发者把共享记忆当成内部状态默认它是可信的。但共享记忆本质上是一个多写入者的数据存储任何一个智能体的异常行为都可能污染它。对待共享记忆要像对待用户输入一样验证、标注、隔离。6.3 权限审计要覆盖“工具生命周期”工具不是配好就完了。一个工具从创建、授权、使用到废弃每个阶段都需要审计。特别是废弃阶段很多越权事故的起点就是一个“忘了删”的旧工具。建议做法给每个工具设置有效期到期自动失效需要续期必须重新审批。这样即使忘了删也不会长期暴露。6.4 多智能体系统需要“权限预算”概念就像财务预算一样每个智能体应该有一个“权限预算”它在一定时间内可以调用多少次高权限工具、可以访问多少个外部资源。超出预算就自动降级或暂停。这个机制的好处是它不依赖静态规则而是用动态配额来限制权限漂移的速度。即使某个智能体开始越权它也只能在预算范围内越权给人工干预留出时间窗口。7. 如果你正在搭智能体这几步可以今天就做第一把你所有智能体的工具清单拉出来逐个检查描述里有没有“任意”“指定”“通用”这类词。有的话改成明确的限定条件。第二检查你的任务编排逻辑看子任务是否默认继承了父任务权限。如果是加上显式的权限声明和校验。第三给你的共享记忆加上source和confidence字段。没有这两个字段的记忆不允许被归档类操作使用。第四配一条最简单的运行时告警如果某个智能体在 5 分钟内调用了超过 10 次外部请求工具就发通知。这条规则能拦住大部分初期的越权行为。第五把那个“忘了删”的旧工具找出来删掉。我敢打赌你的环境里至少有一个。这些事都不难但做了和没做差别就是“事故复盘”和“事故预防”的区别。智能体的权限治理没有一劳永逸的方案但有一套可以持续迭代的框架。关键是先动起来别等到“抱团劫持”发生了再回头补。