跳到正文
>_ITDITDWeb 安全平台

安全指南

npm 供应链蠕虫:凭据如何在安装时被盗,以及如何防御

2026年8月,ChainDrop 在不到4小时内污染了444个 npm 包,而且这些版本带着有效的来源证明(provenance)发布。它在安装时收集凭据,再用偷来的 GitHub 令牌把你的私有仓库复制成公开仓库。本文说明真正能挡住它的做法。

发布于 2026-08-22 更新于 2026-10-04 最后核实 2026-08-22 3 分钟阅读

本文面向:用 npm 或 pnpm 开发、把代码放在 GitHub 上、或从 CI 部署的人。内容基于安全厂商和研究机构公开的分析,不包含攻击步骤或样本。

发生了什么(ChainDrop,2026年8月)

  1. 2026年8月4日

    维护多个常用缓存类包的一名维护者的 GitHub 账户被盗。攻击者触发这些项目原有的 GitHub Actions 发布工作流,把被污染的版本发布到 npm。
  2. 4小时之内

    444个包、2,212个版本被污染,其中包括每周下载量合计超过5亿次的包。
  3. 安装时

    安装时的钩子收集了 npm、GitHub、云(AWS/GCP/Azure)、SSH 密钥、Kubernetes 和 CI/CD 的凭据——据公开分析,还包括从 CI 运行器内存中抓取的短期 OIDC 令牌。
  4. 随后

    攻击者用偷来的凭据重新发布受害者有权发布的所有包(自我传播),并把收集到的密钥外传到攻击者创建的公开 GitHub 仓库。
444
被污染的包
2,212
被污染的版本
5亿+
受影响包的每周下载量合计
4小时
所用时间

这一类攻击的主要危害:私有仓库被公开

Shai-Hulud 系列蠕虫会用偷来的 GitHub 令牌,把受害者的私有仓库复制成公开仓库——已有报告称仓库名以 -migration 结尾。GitHub 并没有被攻破。从你的笔记本或 CI 运行器里拿到的令牌,以你自己的权限把这当作正常操作来执行。所以“等平台修复”在这里不算防御。

为什么没能挡住

添加依赖 / 在 CI 中安装

↓ preinstall / postinstall 自动运行

任意代码在你的电脑或运行器上执行

↓ 收集 npm / GitHub / 云 / SSH / CI 的密钥

用偷来的令牌执行正常操作

私有仓库被复制为公开 / 重新发布包以传播

安装钩子 → 收集凭据 → 用正常的 API 调用。每一步在技术上都是被允许的行为。

没起作用的

  • 签名和来源证明——在维护者权限下正常签发,所以验证通过了
  • “这是很流行的大包”——被污染的恰恰就是这种包
  • 只靠固定版本——全新安装或下次升级时照样会拉取
  • 等平台修复——被利用的是有效令牌和公开 API

起作用的

  • 默认禁用安装脚本——代码根本不会运行
  • 采用新版本前设置等待期——避开从发布到下架之间的时段
  • 短期、权限范围窄的令牌——限制被盗令牌能做的事和能用多久
  • 限制 CI 运行器的出站通信——堵住外传路径

今天要做的5件事

1

搜索自己的锁文件

检查是否含有已报告被污染的版本(例如 keyv@6.0.0、flat-cache@6.1.24、file-entry-cache@11.1.6)。没有找到是好消息,但第2步之后是为下一次同类攻击做准备,请继续做下去。

2

默认关闭安装脚本

让 CI 使用 npm ci --ignore-scripts;pnpm 则在 .npmrc 中设置 ignore-scripts=true,只对确实需要构建的依赖单独放行。这是价值最高的一项改动,因为它去掉了这类攻击所依赖的执行环节。

3

新版本发布后等几天再采用

不要在新版本一发布就采用——等3到7天就够了。像这次一样,从发布到下架只有几小时到几天时,光是等待就能避开。如果使用自动更新 PR,请把这段延迟写进配置。

2026-09-05 补充:这已经不必靠自觉。Node.js 官方安全指南在供应链对策中列出了用 --min-release-age(npm v11.10.0 及以上)设置依赖等待期,避免安装刚发布的包。**能用配置解决的,就不要靠自觉。**依赖有人记得去做的流程,忙的时候往往会被跳过。

4

盘点令牌,缩短有效期、收窄权限范围

把 GitHub 个人访问令牌从 classic 换成 fine-grained,缩短有效期,并只授权给需要的仓库。不要把 npm 发布令牌一直放在 CI 里。密钥和机密的处理方法见 .env 和 API 密钥有哪些危险和 SSH 密钥的最小权限。目标是令牌即使被盗也造成不了多大损害。

5

检查自己的 GitHub 账户

查找不是你创建的公开仓库(名称以 -migration 结尾、描述陌生的)、你没有添加的 GitHub Actions 工作流、被放进 .vscode/tasks.json 或 .claude/ 的可执行配置,以及不认识的 API 密钥或 SSH 密钥。若要用工具持续监控依赖中的已知漏洞,请看 osv-scanner 入门。

怀疑已感染时,先把顺序弄对

研究人员强调了一点,值得重复:先清除留在机器上的常驻组件(监视令牌的脚本等),再吊销令牌。顺序反过来,常驻组件可能会对吊销作出反应。大致步骤:
1. 断开网络
2. 清除持久化项和可疑文件
3. 按 npm → GitHub → 云 → SSH → Kubernetes 的顺序吊销并重新签发
4. 删除 node_modules 和缓存,重新干净安装
5. 检查自己的公开仓库和包的发布历史

如果没有日志,答案是“不知道”,而不是“没事”。请按已被入侵来处理。

本站的看法:签名证明的是来源,不是安全

多年来,签名和来源证明一直是供应链安全的头号建议——而这次攻击绕过了它们。这并不意外:签名告诉你是谁发布的,而不是内容是否安全。被盗账户签出的签名,既有效又危险。因此我们不把来源证明当作让你安全的控制手段,而是当作事后确定影响范围的调查工具。预防靠的是另外两点:不在安装时执行别人的代码,不把密钥放在那些代码能运行到的地方。

出处

接下来阅读

FAQ

Q为什么运行 npm install 就会被盗走凭据?
A

因为包里可以带有在安装时自动运行的脚本(preinstall / postinstall)。所以添加一个依赖,就等于允许那段代码以你的权限执行。ChainDrop 正是利用这一点,收集了 npm、GitHub、云、SSH 和 CI/CD 的凭据。

Q私有仓库被公开是什么意思?
A

这一类蠕虫会用偷来的 GitHub 令牌,把受害者的私有仓库复制成公开仓库——已有报告称仓库名以 -migration 结尾。GitHub 本身并没有被攻破:从你的电脑或 CI 里拿到的令牌,是以你自己的权限执行这些操作的。所以等平台修复并不能保护你。

Q带有签名和来源证明的包不就安全了吗?
A

这次被绕过的恰恰就是这一点。攻击者利用维护者权限触发了项目原有的发布工作流,因此被污染的版本带着有效的来源证明发布出去。签名证明的是“谁发布的”,而不是“内容是否安全”。被盗账户签出的有效签名,依然是有效签名。

Q今天最值得做的一件事是什么?
A

两件事:默认禁用安装脚本(npm ci --ignore-scripts,pnpm 则设置 ignore-scripts=true),以及不要在新版本刚发布时立刻采用——等几天。前者让代码根本不会运行;后者避开了最危险的时段,也就是从发布到被下架之间的几小时到几天。