20 亿次月下载的 npm 依赖遭投毒:可信发布为何没拦住 Keyv 蠕虫
作者:林岚|OC 开发者生态编辑
林岚
安全公司 Aikido 称,攻击者入侵 Keyv 维护者的 GitHub 账户后,把窃密和自我传播代码写进主分支,再发布带有正规构建来源证明的 npm 版本。受影响范围随后扩大到至少 868 个软件包、1381 个版本,相关软件包合计每月安装量超过 20 亿次。
一句话结论:这次事件没有证明软件溯源无效,而是暴露了它的边界:来源证明可以确认“这个包由哪个仓库、哪次构建产生”,却不能证明被接管的仓库和提交本身没有恶意代码。
Keyv 是一个被大量 Node.js 项目间接使用的键值存储接口,攻击面不只在主包。Aikido 列出的关联包包括 cacheable、cache-manager、cacheable-request、flat-cache 和 file-entry-cache,许多开发者甚至不会在自己的 package.json 里直接看到它们。
恶意版本通过 preinstall 脚本执行 setup.mjs,下载 Bun 1.3.13,再运行约 728KB 的 Math_Symbol.js。这段代码会搜集 npm、GitHub、AWS、Kubernetes、Vault、Stripe 和 Slack 等凭据,以及环境变量、私钥和配置文件;验证令牌有效后,把数据传到公开 GitHub 仓库,并用偷来的发布权限继续感染其他包。

最值得注意的是,被污染版本带有 GitHub Actions provenance。过去开发者会把这类标记理解成“供应链更可信”,但它实际回答的是构建来源和流程是否可追溯。攻击者先控制维护者账户、把代码提交进受信主分支,自动化发布系统随后只是忠实地为恶意输入盖了章。
这也是蠕虫式供应链攻击越来越难靠单点扫描处理的原因。窃密、验证凭据、寻找可发布的软件包、篡改代码和再次发布都可以自动完成。JFrog 在 2026 年 5 月披露的另一轮 Shai-Hulud 活动已经影响 170 多个 npm 包和两个 PyPI 包,说明攻击者正在把维护者身份当成可连续扩张的基础设施。
npm 和 GitHub 今年陆续增加分阶段发布、安装时脚本控制和高影响账户保护,但这些措施必须组合使用。对维护者而言,最关键的是把发布权限从日常账户剥离,限制工作流权限,并在每次发布时审核实际产物;对使用方而言,则要锁定依赖、延迟采用刚发布版本,并默认阻止不必要的安装脚本。
关键事实
- Aikido 称受影响范围至少为 868 个软件包、1381 个版本,合计月安装量超过 20 亿次
- 恶意脚本会窃取多类云服务、代码托管和支付凭据,并使用 npm 发布权限继续传播
- 污染版本拥有 GitHub Actions 来源证明,因为恶意代码已先进入受信仓库和构建流程
- 受影响数字来自安全厂商的持续调查,仍可能随清理和归因更新
OC 判断
provenance 不是“安全认证”,而是一张可验证的物流单。它能阻止产物在构建后被调包,却无法替代维护者账户保护、提交审查和发布产物检查。把一个绿色标记当成包内容无害的结论,正是攻击者可以利用的信任空白。
为什么重要
- 对开发者:需要同时检查直接依赖和传递依赖,尤其是带安装脚本的新版本。
- 对企业:应把 npm 令牌、云凭据和 CI 权限按最小权限拆分,避免一次工作站失守扩散到多个系统。
- 对生态:开源包的下载量不能转化为维护资源,少数账户仍承载着数十亿次安装的系统风险。
评论
围绕这篇文章补充信息、提出问题或分享观察。