AI 编码助手可能生成不存在的第三方包名,攻击者可注册这些幻觉名称进行供应链攻击,研究者已发现某些名称被多个模型反复建议。
比起更为人熟知的"传统"版本—— typosquatting(域名仿冒),这种攻击手法的运作逻辑恰好相反。Typosquatting 依赖开发者输错包名,比如把 requests 打成 reqeusts,攻击者抢注这个拼写错误的包名来截获错误。Slopsquatting 则翻转了错误的源头:不再是人为的笔误,而是 AI 编程助手凭空编造出一个听起来合理但根本不存在的包名。研究代码生成模型的学者发现,某些被 hallucinate 出来的包名会在多次独立生成中反复出现,意味着同一个虚假名字会被同时推荐给多位不同的开发者。
这种可重复性正是该攻击值得投入的原因。攻击者无需猜测拼写错误,只需运行研究者们用过的相同提示词,收集多个模型一致 hallucinate 出的名字列表,然后提前在真实包注册平台上注册这些确切的名字。接着就是等待。每一位把这个建议复制进安装命令而未加核实的开发者,都可能成为受害者——而这位开发者根本没有拼错任何东西,他完全像信任 AI 助手其他正确建议一样信任了这条输出。
以这种方式注册的恶意包,不需要看起来可疑。它可以有一个合理的名字、听起来靠谱的描述,甚至包含功能正常的代码,做的是那个虚假包暗示用途所应做的事,同时暗中附带攻击者真正想执行的恶意 payload。代码审查在传统意义上很难 catch 住这种情况,因为 review 者通常只关注新依赖在 diff 中如何被使用,而不是独立核实该依赖本身是否合法。这条关键的信任边界,实际上在大多数团队已做的代码审查之下一层。
那种希望通过不信任 AI 建议来解决问题的本能,通常错过了真正的教训。同样的核实缺口在 AI 编程助手出现之前就存在了——攻击者在拼错的包名上 squatting 的做法已经多年。这种攻击方式改变的是攻击面的规模和可预测性,而非根本性的修复方案。修复方案始终如一:在依赖进入项目之前,根据实际注册平台核实它,检查它的下载历史和维护信号,不要因为一个包出现在建议中——无论多么笃定——就省略这一步。
安全团队多年来在软件供应链安全这一更大范畴下记录了类似的供应链风险,缓解 typosquatting 的实践基本可以直接迁移到 slopsquatting:注册平台核实、下载和 maintainer 历史检查,以及在 lockfile 变动前需要 review 的机制。
静态安全扫描器可以标记出新增依赖中下载量异常低或发布日期极近的情况——这恰恰是 squatting 包的典型特征。Snyk 这类工具将依赖漏洞和信誉扫描直接集成到 CI 流水线中,在 Pull Request 阶段 catch 可疑的新依赖,而不是依赖开发者每次手动检查。将自动化扫描器与针对任何真正陌生内容的人工抽查策略搭配,可以在覆盖大部分现实攻击面的同时,不会在明显安全的包上拖慢团队速度。
大多数团队在供应链风险方面已经具备某种肌肉记忆,即使从未明确这样称呼它。固定依赖版本号、review 新包的 postinstall 脚本在做什么、对只有一个 maintainer 且近期无提交的库保持警惕——这些做法早于 AI 编程助手出现。Slopsquatting 不需要学习新的防御方法,而是需要更一致地应用现有方法,尤其在有新依赖进入项目的那个时刻——无论名字是由人还是助手建议的。
令人不安的是,这种攻击的规模是旧有供应链攻击难以企及的。Typosquatting 依赖人犯拼写错误,这种随机性 inherent 限制了攻击者的 targeting 效率。而多个 AI 模型对同类型提示独立建议出的 hallucinate 名字,是一个可预测得多 target,这正是研究者将其标记为独立、高杠杆的旧问题变体而非小 variation 的原因。
想象一个开发者向助手询问 Python 中轻量级重试失败 HTTP 请求(指数退避)的方案。返回的是一个看似合理、格式规范的推荐,提到了一个听起来完全应该存在的包——比如一个具体名字的 retry 工具。如果该名字恰好是模型在那种提示下经常建议的,而攻击者已经抢先注册了,那么安装命令拉取的就是带真实 payload 的真实代码,而从开发者角度看整个过程毫无异样。这就是完整攻击——没有钓鱼邮件,没有社交工程,只是一个在有人快速行动时听起来合理的名字。
具体机制在不同生态中略有差异,但根本缺口——模型建议一个听起来合理的依赖而不与真实注册平台核实——存在于所有存在包管理器的场景。Rust 的包注册平台、Go 的模块代理、RubyGems 都面临相同的理论暴露,而且研究者已经在多个生态和多种语言中发现了 hallucinate 的引用,不只限于最常讨论的那两种。任何认为这只是特定语言包管理器 narrow 问题的团队,拿的是一张过时的问题图景。
以上都不是回避 AI 编程助手的理由——生产力提升是真实的,绝大多数建议也是正确的。这是一份理由,让"核实依赖"成为团队采用这些工具时 non-negotiable 的一步,就像采用持续部署的团队必须在能安全地在每次合并时发布之前建立自动化测试一样。工具和工作流都需要跟上助手所实现的速度,否则速度只是把风险进一步推向下游,而非消除它。
扫描器和 CI 检查很重要,但更深层的修复是一种团队文化:把"核实新依赖"当作完全正常、毫不稀奇的一步,而非只在出过事后才想起的事前准备。较早建立这种习惯的团队——在任何事件迫使其展开对话之前——往往会一致地应用它,而不觉得是 overhead。那些只在 reactive 情况下——在已经出问题之后——才采纳它的团队,通常应用得不够一致,把它当作对特定惊吓的临时反应,而非评估未来任何新依赖的永久一部分。
137Foundry 对两种 hallucination 失败模式——虚构包和虚构方法调用——有完整 breakdown,以及在到达生产环境之前 catch 住各自的特定检查点,涵盖了从注册平台核实到自动标记 hallucinate API 调用的类型检查工具的一切。