不用一行恶意代码,就能教坏你的 AI Agent:SkillPoison 只用了 15 条『成功经验』

0 阅读1分钟

💡 一句话总结:吉林大学团队的 SkillPoison(arXiv 2610.07645)展示了一种新的 Agent 技能库投毒方式——不注入任何恶意内容,每条投喂经验都任务正确、验证通过、词法干净,只是精心挑选+注释,就能让技能提取器自己「悟」出一条坏规则,攻击成功率最高 95.71%。

你的 Agent 正在写自己的「武功秘籍」

先说背景。现在的 Agent 圈有个很热的方向:自进化。

Agent 干完活会把成功经验存下来,蒸馏成一条条可复用的「技能」(skill)——类似把「这次我怎么改好了这个 bug」抽象成「遇到这类 bug 该怎么改」的攻略。下次遇到类似任务,直接翻攻略,不用重新推理。Claude Code 的 skills、各家 Memory 系统、Agent Workflow Memory,走的都是这个路子。

好处显而易见:越用越快、越用越省 token。

但你想过一个安全问题吗——这些攻略是谁写的?

如果攻略本身被污染,Agent 会把错误的行为当成「经验之谈」反复执行,而且污染会随着技能复用跨任务传播。这就是技能投毒(skill poisoning),一个正在快速升温的研究方向。

现有的投毒手段,其实挺笨的

已知的技能攻击分两派:

一派是直接改技能文件(artifact-based):往技能里塞恶意指令、恶意代码。简单粗暴,但问题是——你得先拿到技能文件的写权限。而新一代自进化 Agent 都是自己创建、自己管理技能的,攻击者根本摸不到文件。

另一派污染学习过程(formation-based):不碰最终技能,而是在「经验→技能」的蒸馏环节下手,往轨迹里注入恶意行为或触发器(代表作 SkillJack、PoisonedEvolution)。

第二派看起来聪明,但吉林大学团队做了一组预实验,结果相当打脸:把这两位选手放到真实的技能形成管线(Trace2Skill 和 AutoSkill)上跑,36 次攻击里 24 次直接被安全机制拒收,9 次只保留了一半恶意行为,真正完整「投毒成功」的只有 3 次。

为什么会这么惨?论文总结了两个先天缺陷:

  1. 恶意行为藏不住。你往轨迹里塞的恶意内容和原任务要求天然冲突,轨迹分析和形成期验证一眼就能看出「这条经验不对劲」。
  2. 失败经验教不会人。这条更致命:技能形成管线只巩固「验证过的成功经验」。你的恶意行为一旦把任务搞砸了,这条失败轨迹对技能形成几乎没有正向贡献——攻击在任务层「生效」了,在技能层却「失忆」了。

一句话:你想教 Agent 学坏,但你的教材(失败轨迹)压根不够格进入它的书架。

SkillPoison 的思路:坏的不是行为,是「语境」

SkillPoison 团队想明白了一件事:为什么要注入恶意行为?一个本身正确的行为,被用错了地方,一样是灾难。

举个栗子:「遇到并发问题先加锁」是一条正确的工程经验——在共享资源冲突的场景下。但如果你的团队新人把它泛化成「所有问题都先加锁」,那就是灾难。行为没变,适用条件丢了。

SkillPoison 就是这么干的。它的目标不是让 Agent 学会一个恶意行为,而是让 Agent 把一条局部正确的规则泛化成全局规则——剥离掉它的适用条件。

两种技能攻击范式对比:显式注入(上)会在验证环节被拦,SkillPoison(下)用验证通过的成功经验诱导泛化

整个攻击分三步,全程没有一个字是「恶意」的:

第一步:挑任务,而不是改任务

攻击者有一个目标行为 p⋆(比如「回答前先复述用户输入」这种看着无害的行为),他不把它塞进任何任务里,而是筛选:哪些任务的执行轨迹里天然就包含这个行为、而且这个行为对任务成功影响很大?

怎么量化「影响大」?做个反事实实验:把 p⋆ 换成一个普通的等价行为,对比输出变化多少。变化大的留下,小的扔掉。留下来的任务,全都「真实验证通过」。

第二步:给成功「记功劳」

光有成功轨迹还不够——一条轨迹里有那么多行为,凭什么让技能提取器注意 p⋆?

SkillPoison 用 LLM 给每条入选轨迹生成一份归因注释:这个任务要求什么、p⋆ 在哪里被用了、它怎么导致了成功、为什么换成别的行为结果会变差。这份注释跟着经验一起进入形成管线。

注意细节:执行和输出一个字没改,只是多了一份「功劳簿」。所有注释内容都是真的——p⋆ 确实参与了任务、任务确实成功了。

第三步:跨任务反复投喂

一条经验只能证明「p⋆ 在这个任务里有用」。SkillPoison 把归因后的经验按任务类别分桶、跨类别组池,让提取器看到:p⋆ 在推理任务里跟成功相关、在写代码任务里跟成功相关、在分类任务里跟成功相关……

于是提取器「归纳」出一个结论:这是个通用好习惯!——泛化完成,适用条件被剥离,一条过泛化的技能就此入册。

SkillPoison 框架:分层任务选择 → 局部证据归因 → 跨经验归纳强化

效果有多吓人?

实验设置:3 个数据集(自然语言推理 HANS、改写识别 PAWS、pandas 代码生成 DS1000)× 2 个技能形成框架,受害者模型 deepseek-v4-flash,攻击预算只有 15 条成功经验。

结果,在全部 6 个「数据集 × 框架」组合里,SkillPoison 的攻击成功率(ASR,越高代表攻击越危险)全部第一,比最强的现有技能攻击高出 2.16–22.35 个百分点。最夸张的一组:PAWS + Trace2Skill,ASR 95.71%——而所有注入的经验,全部保持任务正确、全部通过验证和词法检查。

也就是说:事后任何人去审计那些被投喂的经验,看到的都是一条条「合法、正确、有用」的数据。

还有一个值得细品的观察:很多现有攻击(比如 OEP)的「规则采用率」很高(98%+)但攻击成功率很低(6%)——规则被 Agent 采纳了,却只在很窄的条件下被真正执行。「学会了」和「用它使坏」是两回事,跨经验的支持不足,行为就被困在局部。这也反过来说明了 SkillPoison 第三步(跨任务强化)的必要性。

预算方面:从 5 条经验加到 15 条,PAWS 上的 ASR 从 0–29% 一路涨到 84–96%。多喂几条,攻击就稳了。

泼盆冷水:它其实「响」得很

先别慌,这个攻击有个很明显的软肋。

SkillPoison 在把 ASR 拉满的同时,任务准确率也同步崩了——还是那组 95.71% 的实验,任务准确率从 78.57% 跌到 3.81%。也就是说,被投毒的 Agent 在下游任务上会大面积翻车。在有基本输出质量监控的生产系统里,这种「隐蔽」其实响得像装修。

真正危险的低慢攻击(比如只让准确率悄悄掉 5%)需要精细控制任务损失,论文没做这个。另外,攻击前提是攻击者能影响哪些经验进入形成集——在共享环境、技能市场、多人共用的 Agent 平台里这是现实威胁,但对你独享的、封闭运行的 Agent,攻击者没有这个立足点。

还有一点要说明:实验只覆盖了 3 个数据集、2 个框架、1 个受害模型,换成更强的模型或者更复杂的商业技能管线(比如 Claude Code 的 skills 生态)会怎样,还是未知数。

那防御方该看哪?

论文自己在结论里点了一句方向,值得展开:技能形成时,别只记「什么行为导致了成功」,还要记「在什么条件下有效」——把适用条件(precondition)作为技能的一等公民保存下来,泛化时强制携带。

再进一步,我们可以从这篇论文里多读出几条:

  1. 归因注释是审计入口。SkillPoison 的第三步要给经验附「功劳簿」——反过来,形成管线对「频繁出现的、强调某个行为重要性的注释」应该提高警惕,尤其是来自外部来源的。
  2. 来源审计比内容扫描靠谱。本文证明内容扫描(验证、词法检查)防不住这种攻击,因为它真的一切正常。追踪「这些经验是谁提供的」,比扫描「经验内容是否恶意」更接近问题根源。
  3. Adoption 和 ASR 要分开测。做安全评测的团队注意:只看「规则被采纳率」会严重误判风险——采纳不等于危害。

写在最后

技能生态正在变成 Agent 领域的「应用商店」:Claude Code 有 skills 市场,各家框架都在推技能共享。SkillPoison 提醒我们的是:这个生态的信任模型还是「内容审查」式的,而攻击已经进化到「数据投喂」式了。

当一条经验本身无懈可击时,问题就不再是「这条经验是坏的」,而是「这些经验组合在一起,教会了提取器什么」。

对你的 Agent 攻略库,多问一句:这些攻略,都是谁写的?


资源块

  • 论文:SkillPoison: Progressive Skill Poisoning via Successful Experiences(arXiv 2610.07645)— arxiv.org/abs/2610.07…
  • 代码与数据:github.com/DEEP-JLU/Sk…
  • 相关阅读(同方向攻击研究):SkillJack: Persistent Skill Backdoors in Self-Evolving Agents(arXiv 2608.03509)、PoisonedEvolution / When Experience Becomes Instruction(arXiv 2608.05563)