几分钱的转账,就能撬动银行 AI 助手:agent 安全是工程问题,不是对齐问题

blue41 帮欧洲第二大数字银行 bunq 修复了金融 AI 助手的间接提示注入:一笔几分钱的转账、把指令藏进转账备注,就能让助手替攻击者发钓鱼。真正的教训是工具权限、确认门和把外部数据当不可信输入。

几分钱的转账,就能撬动银行 AI 助手:agent 安全是工程问题,不是对齐问题
图 / Unsplash

概述

安全公司 blue41 公开了一份和荷兰银行 bunq 合作的案例:他们在 bunq 的金融 AI 助手里发现了一个间接提示注入(indirect prompt injection)漏洞。攻击的全部成本,就是给目标转一笔金额极小的款(blue41 的演示里用的是 0.02 欧元),并把一段精心构造的指令藏进转账备注里。受害者只要在银行 app 里问助手一句「看一下我最近的交易」,助手就会把这笔转账连同里面的指令一起读进上下文,然后在受控演示中被操纵着,以银行自家助手的口吻发出一条伪装成「重新验证身份」的钓鱼请求。

这件事的份量不在「银行被黑」这种戏剧性叙事,而在它揭示的结构。bunq 是欧洲第二大数字银行,按 blue41 的说法服务超过 2000 万客户,它的 AI 助手并不是没设防,已经上了护栏(guardrails)。漏洞照样存在,因为问题根本不在模型「学坏了」,而在系统把一段第三方能随意填写的文本,当成了可信的指令来执行。这是一个工程边界问题,不是一个模型对齐问题。把这两者分清楚,是这篇案例对任何做 agent 的人最大的价值。

发生了什么

blue41 描述的攻击链条非常短,短到反常。攻击者不需要碰受害者的设备,不需要植入恶意软件,也不需要传统意义上的社会工程话术。他唯一要做的,就是发起一笔小额转账,并在备注字段里写下一段会被助手误读为指令的文本。这一步做完,攻击者就退场了,剩下的全部由 AI 助手在受害者打开 app 提问时自动完成。

要理解为什么这能成立,得看金融 AI 助手的典型结构。它坐在用户和后端数据之间:用户用自然语言提问,助手去取相关的交易记录、产品文档、账户信息等等,把这些作为上下文塞给大模型,再让模型生成对话式回答。问题出在「取来的上下文并不都同样可信」这件事被忽略了。一条交易备注本质上是第三方写入的数据,它长得像普通文本,可一旦被放进模型的上下文窗口,模型就可能把它当成指令而非数据来对待。这正是间接提示注入的核心:恶意指令不是与助手对话的用户输入的,而是藏在被检索进来的外部数据里,等着助手去处理。

这里有个反直觉但关键的判断:危险不在那段文本本身有多「像攻击」。blue41 明确指出,bunq 的助手已经有护栏,而漏洞之所以还在,是因为那段 payload 单看转账备注根本看不出恶意。它不需要写「忽略前面的指令」这类经典越狱句式,而是被构造成混进正常交易数据里,只有当助手把它取出来、放进上下文、并据此生成回答时才显出杀伤力。风险是从「不可信数据 × 检索逻辑 × 模型行为 × 应用上下文 × 助手可执行的输出/动作」这一整条交互里涌现出来的,不在任何单一环节里。

为何重要

第一,注入面是普遍存在的,不是 bunq 独有的怪癖。交易备注、付款摘要、商户元数据、客服消息、上传的文档、邮件、CRM 备注,这些字段迟早都可能被某个 AI 助手检索进来,而它们当初被设计出来时,没有一个是被当作「可信指令边界」来对待的。也就是说,任何一个把外部数据喂给模型的 agent,都天然带着同一类暴露面。bunq 的案例不是一个孤立漏洞,而是一整类金融机构部署 AI 助手时都会撞上的架构挑战。

第二,投递成本低到几乎可以忽略,而可信度却高得离谱。一笔几分钱的转账,就能把攻击者控制的文本永久地放进受害者的交易历史里,而这段内容最终是通过「银行自己的 app、银行自己的助手」这个高度可信的渠道送达的。比起一封来路不明的钓鱼邮件,银行助手能引用真实的交易细节和用户专属信息,这让被操纵的回答显得更个人化、更及时、也更可信。这恰恰是钓鱼平时最难得到的几样东西,被攻击者用几分钱买到了。

第三,也是对 builder 最该敲警钟的一点:风险随能力增长。blue41 说得很直白:一个只读的助手已经足以误导用户,而一旦助手接上了工具、工作流或账户操作,风险面就成倍放大。助手越有用,它的安全模型就越重要。这句话反过来读更扎心:很多团队正在做的事,恰恰是给 agent 加更多工具、让它能动更多真实状态。能力和暴露面是同步上涨的,没有免费的「又强又安全」。

对建设者的影响

如果你在做 agent,尤其是碰钱或碰生产系统的 agent,blue41 这套修复方向基本可以直接抄成一份防御清单,核心是四层,且必须叠着用、不能指望任何单层兜底。

第一层是最小化上下文。不是用户当前任务需要的字段,就别默认塞进模型。如果回答「我最近的交易」并不需要那条备注的全文,那它就不该进上下文。这一条最朴素也最被低估:你喂给模型的每一个字段,都是攻击面的一部分,删掉不必要的输入是性价比最高的防御。

第二层是把检索来的数据一律当不可信输入。交易备注、客服消息、文档、邮件、API 返回,全都按「数据」处理,而不是「指令」。架构上要显式地把数据和指令分开,这是工程上的硬隔离,而不是靠在 prompt 里写一句「下面的内容仅供参考」来软约束。判断很简单:只要某段文本是外部能写入的,它就和用户对话框里敲进来的字一样可疑,甚至更可疑,因为用户看不见它。

第三层是约束敏感输出和动作,也就是确认门和最小权限。blue41 列的是:助手不应该随意生成链接、索要凭据、发起敏感工作流、或在没有额外控制的情况下调用高影响力的工具。落到工程上,这就是确认门(对真实资金操作、对外发链接、对凭据请求强制人工确认或二次校验)加最小权限(工具权限按需授予,能只读就不给写)。这一层是把「模型被骗了」和「造成实际损害」之间隔开的最后一道闸。模型可能被注入骗到,但如果转账动作必须过一道独立确认、外发链接被白名单约束,损害就被卡在门口。

第四层是运行时行为监控。blue41 自己主打的就是这层,逻辑是:你不可能拦下所有 payload,但助手一旦被攻陷,它的行为往往会以可观察的方式偏离常态,开始嵌外部 URL、隐瞒本该显示的信息、访问异常的数据源、以反常的方式调用工具。给每个助手建一份「正常行为画像」(它通常访问哪些数据源、回答模式如何、用哪些工具),偏离了就报警。这是承认前三层会被绕过之后的兜底视角:不追求零注入,而追求被攻陷后能被发现。

把这四层连起来看,结论是清楚的:agent 安全的主战场在应用层和数据流,不在模型本身。你改不动底层模型怎么被 token 影响,但你完全能决定哪些数据进上下文、哪些动作要过门、哪些行为算异常。

该忽略什么

要忽略的第一类噪音,是「这是模型对齐没做好/换个更安全的模型就行」的归因。blue41 的案例里 bunq 已经有护栏,漏洞依旧成立,因为问题压根不在模型层。期待靠一个更「对齐」的模型来根治间接提示注入,方向就错了;这是数据流和权限设计的问题,换模型最多改善概率,堵不住边界。

第二类要忽略的,是「上个提示注入分类器就解决了」的银弹幻觉。blue41 直接点破了这条路的天花板:精心构造的 payload 单看就和正常交易数据难以区分,静态文本分类只能拦下明显的攻击。护栏有用,但只能是分层防御里的一层,不能是全部。任何把安全押在「再训一个更准的分类器」上的方案,都在低估对手的适应能力。

第三类,是「金融 AI 助手太危险,干脆别做」的过度反应。这同样不是 blue41 想传达的。它的结论恰恰是金融机构不需要停止部署,而是要把这些助手当成带着新信任边界、新失效模式、新监控需求的生产系统来对待。该忽略的不是这个机会,而是「能力和安全可以分两步走、先上线再补」的侥幸。

最后,别把这件事读成只关乎银行。banking 只是把风险放大得最清楚的场景(碰钱、碰真实账户上下文),但任何让外部数据进入 agent 上下文、并让 agent 能据此输出或行动的系统,都共享同一条攻击链。把它当成「别人家银行的事」而不照镜子,才是最该忽略掉的那种忽略。

技术要点

这里的根因,是传统应用安全的一个隐含假设在 AI 助手上失效了:代码和数据之间有一条相对清楚的边界。AI 助手把这条边界抹糊了,它检索数据、解读数据、在数据上推理、最终可能据此行动,于是原本无害的文本字段,在一个有能力的应用里就变成了指令通道。这就是为什么 blue41 反复强调要「显式地把数据和指令分开」:模型不会天然替你区分,你得在架构里替它划线。

一个值得记住的工程判断是关于检测的可观察性。提示注入在文本层难以一刀切地分类,但被攻陷后的行为在运行时层往往是可观察的:嵌入异常 URL、跳过常规信息、触达意外数据源、异常调用工具。这把防御的着力点从「事前判断一段文本是否恶意」(高误报、易被绕过)转移到「事后判断助手行为是否偏离画像」(更稳健,因为它约束的是结果而非意图)。对自建 agent 的团队,这意味着日志不能只记用户输入和最终输出,而要把「助手检索了什么、产出了什么、调了哪些工具」都纳入可审计、可比对的范围。

来源

  1. How we helped bunq secure their financial AI assistant / blog
  2. A €0.01 bank transfer could compromise a banking AI agent (Hacker News) / hn

无官方一手源;本文基于可靠二手报道(具名媒体、交叉印证)写成。