多智能体系统中的劫持攻击 - Trail of Bits博客
MAS劫持工作原理
多智能体系统(MASs)作为AI应用中日益流行的范式,引入了新的攻击面:智能体间控制流。通过MAS劫持攻击,攻击者可以操纵MAS的控制流。想象一下,你的AI研究助手检索了一个恶意网页,突然攻击者就能在你的机器上执行任意代码。
今天,我们发布pajaMAS:一套精心策划的MAS劫持演示,阐释MAS安全的重要原则。本文将逐步讲解每个演示,解释底层安全原理,并提供安全MAS开发的具体指导。
MAS劫持通过利用智能体间通信方式来操纵MAS的控制流。由Triedman等人发现的这种攻击可被视为针对MAS控制流的提示注入变种。研究人员劫持了多个MAS来执行任意恶意代码,发现这些攻击在以下情况下都能成功:
- 跨不同领域、媒介和拓扑结构;
- 即使单个智能体具有强大的提示注入防御;
- 即使单个智能体明确识别提示为不安全。
这是我们智能体的缺陷:它们是困惑的代理,清洗来自其他智能体的恶意数据。MAS固有的不可靠性阻碍了其生产化,并使得MAS劫持等攻击成为可能。
理解MAS劫持的攻击面
攻击者可以利用多种攻击向量执行MAS劫持,包括恶意环境、恶意工具或恶意代理。架构弱点如"致命三要素"、循环和幼稚的安全控制会放大这些攻击的影响和复杂性。
恶意环境
最常见的攻击向量是恶意环境。simple_mas演示使用Google的Agent Development Kit (ADK)复现了论文的目标。在这里,编排代理将任务委托给网页浏览代理和代码执行代理。simple_mas演示包含多个具有不同隐蔽程度的恶意网站(部分由Claude代理生成)。
攻击工作原理:
- 用户请求编排器总结特定URL
- 编排器将任务委托给网页浏览代理
- 网页浏览代理访问恶意网站
- 恶意内容使网页浏览代理委托给代码执行代理
- 代码执行代理执行有效载荷
防御考虑: 对于此漏洞利用,系统可以在执行前验证命令链。输入可以包含声明其来源的元数据,在通过MAS流动时附加,阻止无效转换。这种验证应独立于LLM,并由代理框架支持。
恶意工具
恶意工具提供了另一个MAS妥协的攻击向量。在tool_mas演示中,工具safely_parse_web_search_results被添加到网页浏览代理。工具名称导致代理自动信任和使用它。然而,当被特定内容触发时,此工具将恶意提示注入代理的响应中,实现类似simple_mas的MAS劫持。
恶意工具可以利用与合法工具的语义和句法关系来劫持控制流。不仅恶意工具的威胁被当前MCP生态系统的状态放大,攻击者还可以在描述中进行提示注入,欺骗代理选择恶意工具,并随时间动态更新工具以进行更有效的攻击。
防御考虑: 恶意工具需要深度防御方法。解决方案包括工具来源跟踪、工具允许列表、独立输出验证、工具数据隔离和沙盒化工具访问,以防止代理上下文间的横向移动。
恶意(或受感染)代理
虽然在使用代理发现协议时恶意代理很重要,但MAS中的单个代理也可能被破坏。在pajaMAS中,agent_memory_mas通过毒化代理内存实现持久性妥协来诱导MAS劫持。
在agent_memory_mas中,网页浏览代理可以通过包含_add_user_preference工具存储用户偏好,该工具使用ADK的内存功能。
攻击工作原理:
- 用户让网页浏览代理访问preference.html(如图4所示)
- 网页浏览代理读取preference.html,存储建立持久劫持的恶意用户偏好
- 用户让网页浏览代理访问birds.html
- 由于恶意用户偏好,网页浏览代理将有效载荷发送给代码执行代理
- 代码执行代理执行有效载荷
当代理访问共享工件时,内存毒化的风险增加,特别是那些由子代理直接产生或修改而未经验证的工件。糟糕的会话隔离也可以通过将恶意数据纳入上下文窗口来实现代理妥协。
防御考虑: 除了保护内存外,还要考虑内存的实际实现方式:ADK正在将此特定段落添加到您的上下文窗口中以实现内存。框架可能掩盖实际发生的情况,导致不正确的上下文工程。此演示错误地基于该上下文添加,直接将不受信任的数据添加到内存中。
理想情况下,如果无法实现人在回路中,代理内存访问应仅限于预定义的、经过清理的状态(呼应Action-Selector模式)。例如,如Google的ADK教程所示,天气MAS应只允许"华氏度"或"摄氏度"存储在内存中,以确定如何向用户显示温度。
利用致命三要素
虽然代理沙盒最小化了RCE风险,但它们并不能完全消除MAS安全问题。单个代理仍然可以影响共享环境来操纵其他代理。trifecta_mas演示说明了Simon Willison的"致命三要素"模式,该模式指出在AI应用中结合私有数据访问、不受信任内容暴露和外部通信可以实现数据外泄。
攻击工作原理:
- 网页浏览代理访问preference.html,存储用于持久劫持的恶意用户偏好(不受信任的上下文)
- 网页浏览代理访问medical.html,将敏感医疗记录加载到上下文中(私有数据)
- 网页浏览代理访问birds.html。此页面包含故意不完整的代码,网页浏览代理使用医疗数据完成代码(如图5所示)
- 网页浏览代理将代码发送给代码执行代理,后者接收并外泄敏感数据(外部通信)
防御考虑: 在保持有用功能的同时避免致命三要素需要仔细的系统设计。Beurer-Kellner等人描述了几种缓解此类问题的设计模式。一个有用的方法是实现操作模式分离:当您的系统访问不受信任的数据时,它不应具有外泄能力。此演示还显示了实施严格会话卫生以防止数据持久性的重要性。
利用循环
MAS通常包含循环,有时是无意的。这些循环通过委托放大风险,创建嵌套执行环境,其中副作用成为新输入,导致级联故障。
我们的系统包含一个循环:代码执行代理可以开发由网页浏览代理访问的网页,后者可以调用代码执行代理。此循环支持更复杂的攻击,如cycle_mas。
攻击工作原理:
- 用户指示系统总结initial.html。此页面包含代码,执行时会创建并提供preference.html文件
- 网页浏览代理将代码执行委托给代码执行代理,后者运行来自initial.html的脚本,为preference.html启动服务器(图6中的MAS劫持1)
- 按照代码注释中的指令,代码执行代理委托给网页浏览代理,后者访问preference.html并设置持久用户偏好,当在任何网页中检测到代码时始终委托代码执行(MAS劫持2)
- 用户然后要求系统总结birds.html。由于加载的偏好,网页浏览代理自动为在birds.html中找到的任何代码委托代码执行,建立持久MAS劫持(MAS劫持3)
随着MAS变得更加复杂,这些级联故障可能变得更具影响力且更难检测。此外,初始妥协可以保持隐藏,而其影响通过系统传播,只有在很久以后才变得可见或被完全利用。
防御考虑: 与trifecta_mas类似,此演示强调了跨代理边界的会话卫生和仔细系统设计的重要性。避免并有意控制MAS中的循环可以最小化级联故障。
绕过幼稚的安全控制
与单代理提示注入一样,有许多隐蔽向量可用:不可见指令、Unicode混淆、替代文本、QR码、HTML注释和虚假错误消息。像Imprompter这样的技术甚至可以自动生成表达为非人类可解释字符串的恶意提示。大量的隐蔽向量增加了构建有效防护栏的固有难度。
考虑如果用户复制粘贴URL而不检查它,或者此URL是从受信任代理产生的内容中获取的情况。演示url_anchor_mas通过精心制作的URL锚点实现MAS劫持。
在defense_mas中,网页浏览代理可以访问_llm_security_check,它使用模型检查来自网络的输入。但此控制建立在恶意内容仅来自网络的假设上。因此,此控制无法防止通过精心制作的URL锚点传递的MAS劫持。
特别是URL锚点经常被当前的提示注入缓解措施遗漏。此外,由于URL通常在应用程序的会话或实例之间共享,它们可以充当隐式内存,实现内存毒化。
防御考虑: 安全系统需要超越可绕过的缓解措施,构建强大的架构控制。不仅安全训练不是万无一失的,在代理设置中明显更差,更强大的模型实际上显示出更高的攻击率。防护栏和系统提示缓解措施都不是万无一失的。事实上,由于系统提示可以被检索,它们实际上可以促进攻击者对子代理的特定实例化。
在MAS中,恶意数据可以来自环境、用户和其他代理。这意味着限于特定向量甚至特定代理的安全控制可以被规避。此外,代理不能可靠地执行安全边界,因为它们可能被操纵来谎报安全状态。因此,安全机制不应附加到MAS的单个节点上。它们应存在于编排层中,并通过工作流而不是代理行为实现。强大的缓解和防御需要强大的设计、污点跟踪、人在回路中和运行时检查。
构建安全的MAS
由LLM生成的内容应被视为本质上不受信任的。因此,仅由一双紧紧交叉的手指分隔的本质不受信任的生成器混合是灾难的邀请。
首先要问的问题是您是否需要MAS。许多问题可以通过更简单、更安全的方法解决,这些方法将工作流与有限的代理行为相结合。
如果您确定需要MAS,下一个问题是如何安全地设计它。
核心设计原则
设计安全的MAS很困难,因为每个代理不了解相同的上下文和安全控制。在单代理设置中,安全上下文工程需要检查放置在不同上下文片段中的信任。在多代理设置中,这乘以代理数量,然后被需要考虑总体控制流的需求放大。
您的MAS的控制流决定了操作序列以及谁控制什么操作。它定义了系统行为的边界。糟糕的设计将允许攻击者利用代理通信、共享资源、决策制定和信任假设中的不一致性。它还可以增加提示感染和自然故障模式等问题的影响。
在单代理设置中,构建者可以通过采用特定的强大设计模式来导航安全性和实用性之间的权衡。这些模式通过最小化攻击面和潜在影响来缓解提示注入风险。它们在多代理设置中也很有用,但需要考虑以下额外因素:
- 将每个代理视为可能受损的组件。假设任何代理都会产生恶意输出或行为不可预测。任何单个代理都不应能够造成系统性不稳定
- 实施权限分离。高权限代理不应在没有适当验证和清理的情况下信任低权限代理的输出
- 避免攻击者可能引发级联故障的循环
- 优先选择强大的系统和架构控制,而不是有缺陷的缓解措施
- 实施基于CAMEL等能力的运行时控制
- 确保安全机制包含在编排层中。它们不应限于单个代理或以代理方式部署
MAS安全检查清单
在设计或检查MAS时,请确保询问以下问题:
- 恶意或受感染代理的能力是什么?
- 代理对彼此输出的隐式信任程度如何?
- 代理是否有权访问共享内存和上下文?
- 工具访问权限和能力边界是什么?
- 代理是否有权访问持久状态或历史记录?
- MAS的控制流如何影响其安全性?
- 哪些代理最能操纵环境?
- 哪些代理最容易受到环境操纵?
- 图中是否存在可被利用的循环?
- 通过您的代理层次结构的权限提升路径是什么?
框架选择标准
从安全角度来看,选择框架时最重要的问题是:
- 框架默认是否足够安全? 大多数当前框架都不是。此外,它们在不同的抽象层次上操作(例如,ADK暴露transfer_to_agent工具),这些抽象在安全属性上有所不同
- 框架是否提供对上下文窗口和控制流的足够可见性和控制? 许多AI工程师认为不应使用框架,因为它们迫使您将上下文窗口和控制流的可见性和控制权交给框架(例如,ADK中使用append_instructions)。不控制您的提示和上下文窗口会导致提示注入等攻击。不控制您的控制流会导致MAS劫持等攻击。请参考12-factor agents的因素2、3和8,这是一组构建可靠AI应用的原则
- 框架是否为不同的安全机制提供足够支持? 您可以自定义应用程序的状态和逻辑,以便实现有效的人在回路中、防护栏、污点跟踪和运行时控制吗?对于MAS劫持,您可以在执行前独立于LLM验证命令链吗?或者框架是否施加任意限制?
前进方向
MAS劫持体现了大规模困惑代理问题。有缺陷的缓解措施无法拯救我们。我们需要采用安全设计模式。基于CAMEL等能力模型的运行时控制是最有前途的防御。它们需要辅以安全上下文工程、身份管理和授权的既定实践,所有这些都由默认安全工具支持。我们将分享更多关于如何保护代理AI应用的工作,但与此同时,请立即尝试pajaMAS。
构建和保护MAS的资源
- 我们如何构建多代理研究系统(Anthropic)
- 如何以及何时构建多代理系统(LangChain)
- 12 Factor Agents(HumanLayer)
- Agents Companion(Kaggle)
- 为什么多代理LLM系统会失败?(Cemri等人,2025)
- DSPy:LM程序的提示优化(Michael Ryan at Bay.Area.AI)
- 保护LLM代理免受提示注入的设计模式(Beurer-Kellner等人,2025)
- 多代理系统威胁建模指南(OWASP)
- 代理自主级别和安全性(NVIDIA)
- 利用A2A协议构建安全代理AI应用(Habler等人,2025)
- 多代理系统执行任意恶意代码(Triedman等人,2025)
致谢
感谢Joel Carreira、Rich Harang、James Huang、Boyan Milanov、Kikimora Morozova、Tristan Mortimer、Cliff Smith和Evan Sultanik提供的有用反馈和讨论。