本文面向:用 npm 或 pnpm 开发、把代码放在 GitHub 上、或从 CI 部署的人。内容基于安全厂商和研究机构公开的分析,不包含攻击步骤或样本。
发生了什么(ChainDrop,2026年8月)
2026年8月4日
维护多个常用缓存类包的一名维护者的 GitHub 账户被盗。攻击者触发这些项目原有的 GitHub Actions 发布工作流,把被污染的版本发布到 npm。4小时之内
444个包、2,212个版本被污染,其中包括每周下载量合计超过5亿次的包。安装时
安装时的钩子收集了 npm、GitHub、云(AWS/GCP/Azure)、SSH 密钥、Kubernetes 和 CI/CD 的凭据——据公开分析,还包括从 CI 运行器内存中抓取的短期 OIDC 令牌。随后
攻击者用偷来的凭据重新发布受害者有权发布的所有包(自我传播),并把收集到的密钥外传到攻击者创建的公开 GitHub 仓库。
这一类攻击的主要危害:私有仓库被公开
Shai-Hulud 系列蠕虫会用偷来的 GitHub 令牌,把受害者的私有仓库复制成公开仓库——已有报告称仓库名以 -migration 结尾。GitHub 并没有被攻破。从你的笔记本或 CI 运行器里拿到的令牌,以你自己的权限把这当作正常操作来执行。所以“等平台修复”在这里不算防御。
为什么没能挡住
添加依赖 / 在 CI 中安装
↓ preinstall / postinstall 自动运行
任意代码在你的电脑或运行器上执行
↓ 收集 npm / GitHub / 云 / SSH / CI 的密钥
用偷来的令牌执行正常操作
私有仓库被复制为公开 / 重新发布包以传播
没起作用的
- 签名和来源证明——在维护者权限下正常签发,所以验证通过了
- “这是很流行的大包”——被污染的恰恰就是这种包
- 只靠固定版本——全新安装或下次升级时照样会拉取
- 等平台修复——被利用的是有效令牌和公开 API
起作用的
- 默认禁用安装脚本——代码根本不会运行
- 采用新版本前设置等待期——避开从发布到下架之间的时段
- 短期、权限范围窄的令牌——限制被盗令牌能做的事和能用多久
- 限制 CI 运行器的出站通信——堵住外传路径
今天要做的5件事
搜索自己的锁文件
检查是否含有已报告被污染的版本(例如 keyv@6.0.0、flat-cache@6.1.24、file-entry-cache@11.1.6)。没有找到是好消息,但第2步之后是为下一次同类攻击做准备,请继续做下去。
默认关闭安装脚本
让 CI 使用 npm ci --ignore-scripts;pnpm 则在 .npmrc 中设置 ignore-scripts=true,只对确实需要构建的依赖单独放行。这是价值最高的一项改动,因为它去掉了这类攻击所依赖的执行环节。
新版本发布后等几天再采用
不要在新版本一发布就采用——等3到7天就够了。像这次一样,从发布到下架只有几小时到几天时,光是等待就能避开。如果使用自动更新 PR,请把这段延迟写进配置。
2026-09-05 补充:这已经不必靠自觉。Node.js 官方安全指南在供应链对策中列出了用 --min-release-age(npm v11.10.0 及以上)设置依赖等待期,避免安装刚发布的包。**能用配置解决的,就不要靠自觉。**依赖有人记得去做的流程,忙的时候往往会被跳过。
盘点令牌,缩短有效期、收窄权限范围
把 GitHub 个人访问令牌从 classic 换成 fine-grained,缩短有效期,并只授权给需要的仓库。不要把 npm 发布令牌一直放在 CI 里。密钥和机密的处理方法见 .env 和 API 密钥有哪些危险和 SSH 密钥的最小权限。目标是令牌即使被盗也造成不了多大损害。
检查自己的 GitHub 账户
查找不是你创建的公开仓库(名称以 -migration 结尾、描述陌生的)、你没有添加的 GitHub Actions 工作流、被放进 .vscode/tasks.json 或 .claude/ 的可执行配置,以及不认识的 API 密钥或 SSH 密钥。若要用工具持续监控依赖中的已知漏洞,请看 osv-scanner 入门。
怀疑已感染时,先把顺序弄对
研究人员强调了一点,值得重复:先清除留在机器上的常驻组件(监视令牌的脚本等),再吊销令牌。顺序反过来,常驻组件可能会对吊销作出反应。大致步骤:
1. 断开网络
2. 清除持久化项和可疑文件
3. 按 npm → GitHub → 云 → SSH → Kubernetes 的顺序吊销并重新签发
4. 删除 node_modules 和缓存,重新干净安装
5. 检查自己的公开仓库和包的发布历史
如果没有日志,答案是“不知道”,而不是“没事”。请按已被入侵来处理。
本站的看法:签名证明的是来源,不是安全
多年来,签名和来源证明一直是供应链安全的头号建议——而这次攻击绕过了它们。这并不意外:签名告诉你是谁发布的,而不是内容是否安全。被盗账户签出的签名,既有效又危险。因此我们不把来源证明当作让你安全的控制手段,而是当作事后确定影响范围的调查工具。预防靠的是另外两点:不在安装时执行别人的代码,不把密钥放在那些代码能运行到的地方。
出处
- Unit 42(Palo Alto Networks)— ChainDrop: Inside a Self-Propagating npm Worm(传播方式、被收集的凭据、指标)
- StepSecurity — ChainDrop npm Worm(检测指标和处置顺序)
- Elastic Security Labs — CHAINDROP worm hits 400+ npm packages
- Node.js「Security Best Practices」— nodejs.org(供应链攻击途径和对策:
--ignore-scripts、锁文件、npm ci、--min-release-age等待期;2026年9月5日确认) - SecurityWeek — Over 400 NPM Packages Infected in ChainDrop Supply Chain Attack(规模和经过)
- Wiz — Shai-Hulud npm Supply Chain Attack(把私有仓库复制为公开仓库的手法)
接下来阅读
- 2026年的案例:TanStack、Nx Console 与 GitHub 的连锁事件——开发者该检查什么
- 实践:用 osv-scanner 持续监控依赖的 CVE / 用 gitleaks 在提交时拦住密钥
- 基础:.env 和 API 密钥有哪些危险 / SSH 密钥的最小权限
- 比较:自建 Git 与 GitHub,哪个更安全
- 经由依赖进来的缺陷:Node.js 中的原型污染(合并函数即使是依赖写的也算在内)
- 术语:什么是恶意软件
- 共同模式:2026年的入侵多从有效凭据进入(同样的形态——被盗的令牌执行普通操作)
FAQ
Q为什么运行 npm install 就会被盗走凭据?
因为包里可以带有在安装时自动运行的脚本(preinstall / postinstall)。所以添加一个依赖,就等于允许那段代码以你的权限执行。ChainDrop 正是利用这一点,收集了 npm、GitHub、云、SSH 和 CI/CD 的凭据。
Q私有仓库被公开是什么意思?
这一类蠕虫会用偷来的 GitHub 令牌,把受害者的私有仓库复制成公开仓库——已有报告称仓库名以 -migration 结尾。GitHub 本身并没有被攻破:从你的电脑或 CI 里拿到的令牌,是以你自己的权限执行这些操作的。所以等平台修复并不能保护你。
Q带有签名和来源证明的包不就安全了吗?
这次被绕过的恰恰就是这一点。攻击者利用维护者权限触发了项目原有的发布工作流,因此被污染的版本带着有效的来源证明发布出去。签名证明的是“谁发布的”,而不是“内容是否安全”。被盗账户签出的有效签名,依然是有效签名。
Q今天最值得做的一件事是什么?
两件事:默认禁用安装脚本(npm ci --ignore-scripts,pnpm 则设置 ignore-scripts=true),以及不要在新版本刚发布时立刻采用——等几天。前者让代码根本不会运行;后者避开了最危险的时段,也就是从发布到被下架之间的几小时到几天。