很多人没有听过 npm,但你每天打开的网站、公司后台和 AI 工具,背后都可能用到了它。
程序员很少从零写完一个软件。读取配置、保存缓存、处理文件这些常见功能,往往会直接使用别人写好的代码。开发者把这些代码做成一个个 package,也就是“代码零件”,放进 npm 这个公共仓库里。
一个项目可能会用到几百甚至上千个零件。有些是开发者主动挑选的,更多藏在“依赖的依赖”里。你没在项目首页见过它,不代表它没有进入软件。
8 月 4 日,这座代码零件仓库出事了。
攻击者先控制了常用缓存工具 keyv 的维护者账号,把恶意程序塞进新版本。这个程序随后偷取其他维护者的发布凭证,继续污染他们名下的软件包。Datadog 目前公开的清单里共有 444 个包,按版本展开有 2236 个受污染版本。
这两个数字统计的是被污染的代码零件和批次。究竟有多少台开发电脑、构建服务器真的运行过恶意程序,目前没有公开的准确数字。
如果你只是打开网站或使用在线版 AI 工具,通常不需要自己检查 npm。开发、构建软件的团队需要行动。在本机使用 Claude Code、Codex 等开发工具的人,还要多检查一步仓库配置。
一个代码零件,怎么把整条生产线拖下水
可以把软件开发想成组装汽车。
npm 是零件仓库,软件包是螺丝、轴承和传感器。CI/CD 是自动装配线:代码一提交,它就自动领取零件、组装、测试,再把软件发布出去。
这次被投毒的包里多了一张“到货后自动执行”的指令。开发者运行 npm install,或者自动装配线更新依赖时,这段叫做 preinstall 的脚本会在安装完成前启动。
它启动后,会寻找电脑和构建服务器里的各种“钥匙”:npm 发布凭证、GitHub 账号令牌、云平台密钥、服务器登录密钥,以及 Claude、Codex、Cursor 等 AI 工具的配置。Token、密钥和令牌可以先理解成电子门禁卡,拿到的人能够进入对应系统,权限高的卡还能发布新的软件版本。
恶意程序拿到 npm 发布权限后,会打开这个账号管理的其他零件箱,也塞入同样的程序,再发布一个看起来很普通的补丁版本。蠕虫就是这样从一个维护者扩散到 400 多个包。
它还会尝试修改 .claude/settings.json 和 .vscode/tasks.json。这两个文件分别控制 Claude Code 和 VS Code 的部分自动动作。被改过的仓库就像在车间门口加了一条指令:有人打开项目,恶意程序可能再次启动。

恶意版本已经下架,为什么公司还要继续查
8 月 20 日,我重新查询了最早披露的 11 个恶意版本,包括 keyv@6.0.0、flat-cache@6.1.24 和 file-entry-cache@11.1.6。它们目前都已经无法从 npm 公共仓库查到,常用版本标签也退回了前一个正常版本。
Keyv 维护者此前表示,他们已经擦除可能受影响的机器,停用自动发布流程,并配合 npm 删除恶意版本。Datadog 的 444 包清单最后更新于 8 月 6 日。我也没有在已经核对的一手渠道中看到 8 月 14 日以后新增的一批受污染包。
已经下架的恶意版本,从 npm 公共仓库已经无法正常下载。此前领进公司的零件不会自动被召回。
package-lock.json、pnpm-lock.yaml 和 yarn.lock 是项目的精确领料单,记录实际使用了哪个版本;CI 缓存像车间旁边的小仓库;基础镜像像反复使用的装配模板;制品则是已经组装完成、准备交付的软件。
Unit 42 记录过一个实际恢复案例:团队把 latest 标签指回干净版本后,旧锁文件、缓存、镜像和下载包仍保留着污染版本。后面的构建继续从这些地方取货,网上商店换了标签也帮不上忙。
不懂安全也没关系,先让团队回答四个问题
如果你是产品经理、项目负责人或者普通 AI 工具用户,可以先把下面四个问题交给开发和安全团队:
- 项目是不是用 JavaScript 开发,并通过 Node.js 这类环境构建?构建时会不会从 npm、pnpm 或 Yarn 下载依赖?
- 8 月 4 日以后,开发电脑或自动构建流水线是否安装、更新过依赖?
- 项目的锁文件、共享缓存、基础镜像里,有没有 Datadog 清单中的精确版本?
- 安装依赖的机器能否读取 npm、GitHub、云平台或业务系统的密钥?
先看第三个问题。package.json 更像采购计划,锁文件才是实际领料单。很多团队从未主动安装 keyv,它仍可能被另一个工具间接带进项目。
可以把 Datadog 维护的受影响包 CSV交给技术同事,也可以连同下面这段提示词一起交给能够读取仓库的 Agent:
请只做只读排查,不运行 npm install、npm ci、npm rebuild、npx,
也不要执行项目脚本或修改、删除任何文件。
1. 读取仓库内所有 npm、pnpm、Yarn 锁文件,与我提供的
malicious-packages.csv 比较包名和精确版本。
2. 列出每个命中的文件、行号和版本,并说明它是直接依赖还是间接依赖。
3. 搜索 setup.mjs、Math_Symbol.js、math_init.js,以及
.claude/settings.json、.vscode/tasks.json 在 2026-08-04 后的异常变化。
4. 列出仓库外仍需人工检查的 CI 缓存、基础镜像和已发布制品。
结果分为:确认命中、可疑但待复核、当前检查没有覆盖。
没有发现命中时,只报告检查范围,不宣称环境安全。
这份检查只负责盘点。锁文件命中说明污染版本进入过依赖树;安装日志、恶意文件或异常网络记录会进一步说明程序是否可能运行过。

查到污染版本以后,先停生产线,再换钥匙
Microsoft 和新加坡网络安全局给出的建议很明确:机器安装过污染版本,并且当时允许安装脚本运行,就按“可能已经失陷”处置。
第一步是暂停相关构建和发布,隔离开发电脑与构建节点,保留日志和磁盘证据。继续在原机器上边查边构建,可能让后续证据被覆盖。
随后要在一台确认干净的机器上撤销凭证。npm 和 GitHub 的发布权限排在前面,因为恶意程序可以拿它们继续污染其他包和仓库;云平台、服务器、容器仓库和 AI 工具密钥,则按照这台机器实际能接触到的范围处理。
最后从可信的代码、锁文件和安全版本重新构建。共享缓存、基础镜像和已经生成的安装包也要检查或重做。删除 node_modules 只是扔掉眼前这箱零件,已经复制走的钥匙不会跟着回来。

npm 12 给代码零件加了一道验货手续
过去,依赖包可以在安装时自动运行 preinstall、install 和 postinstall 脚本。npm 12 默认拦住这些脚本,项目明确批准以后才会执行。它有点像新零件进厂后先放在待检区,确认供应商和用途,再允许接入生产线。
npm 12 对 Node.js 版本要求较新,老项目升级前需要检查兼容性。暂时使用 npm 11 的团队,可以升级到 11.16.0 或更高版本,列出哪些依赖想在安装时自动运行脚本,再逐个审批:
npm approve-scripts --allow-scripts-pending
npm 11 默认只会提醒。团队还要启用 strict-allow-scripts=true,才能让未经审核的脚本直接停止安装。审批时不要图省事使用 --all,那相当于没拆箱就给所有零件盖了合格章。
部分恶意版本带有有效的 npm provenance。Provenance 可以理解成物流单,它能证明这箱货从哪个仓库、经过哪条流水线发出。物流单是真的,箱子里的零件仍可能已经被人换过。
截至 8 月 20 日,Datadog 的公开清单仍停在 444 个包,最早披露的恶意版本已经从 npm 公共仓库移除。没有做过锁文件和 CI 缓存排查的团队,现在仍需要补上这一课。
主要资料
- Datadog:Worm compromises hundreds of popular npm packages
- Datadog:keyv campaign 受影响包 CSV
- Keyv 维护者:Repository and package compromised
- Microsoft:ChainDrop supply chain compromise
- Unit 42:Inside a Self-Propagating npm Worm
- GitHub:npm v12 安装安全变化
- npm 文档:approve-scripts
- 新加坡网络安全局:Ongoing npm Supply Chain Attack
以上就是这次的侦察。
如果对你有用,顺手点个赞 +「♥️」。
想第一时间收到前线情报,关注「硅基斥候S01」。我们,下次侦察见。
