400 多个 npm 包被投毒,看看你有没有被中招


 8 月 4 日,常用 npm 包 `keyv` 的维护者账号被攻破,恶意版本随后像蠕虫一样向更多包扩散。已经安装过受影响版本的开发机和 CI 环境都该按“可能失陷”处理,但这次别急着先换密钥:恶意程序专门埋了一个密钥失效触发器,处置顺序错了,反而可能多挨一下。

先把数字说准:确认的是 400 多个包

这次攻击最早从 keyv@6.0.0 暴露出来。攻击者先控制了维护者的 GitHub 身份,向仓库塞入恶意文件,再借合法发布流程把带毒版本推上 npm。此后,蠕虫利用偷到的 npm 凭据继续寻找受害者名下的其他包,注入相同载荷并重新发布。

维度 截至 8 月 5 日早间可核对的信息
初始入口 keyv 维护者 GitHub 账号被攻破
首个确认恶意版本 keyv@6.0.0
影响规模 Aikido 报告 434 个包、1381 个恶意版本;Wiz IOC 清单有 443 条包记录
下载规模 受影响包合计每月下载量超过 20 亿次,不等于 20 亿次安装都已中招
主要目标 npm、GitHub、云平台、CI/CD、Kubernetes、Vault 和 AI 工具凭据

原推把规模写成了“至少 868 个包”,却没有附上对应清单;这个数字目前也无法和三家安全公司的公开记录对上。可能是统计时间或口径不同,但现阶段不能当成已经确认的事实。更可靠的说法是:至少 400 多个 npm 包已经确认受影响,清单仍在更新。

Aikido 为本轮 Shai-Hulud 攻击制作的主视觉
Aikido 为本轮 Shai-Hulud 攻击制作的主视觉“每月 20 亿次下载”也容易被误读。它说明这些包扎在大量依赖树里,爆炸半径很大;它不是感染设备数,更不能直接当成受害项目数。

它怎么从一次 npm install 里钻进去

恶意版本没有粗暴改掉 keyv 的正常功能。Socket 对包内容做哈希比对后发现,真正的变化集中在 package.json 和两个新增文件里:安装前钩子先运行 setup.mjs,再下载 Bun 1.3.13,执行约 728 KB 的第二阶段载荷 Math_Symbol.js

"scripts": {   "preinstall": "node setup.mjs" } 

这段载荷会搜 npm、GitHub、AWS、GCP、Azure、HashiCorp Vault 和 Kubernetes 凭据,也会翻找 Claude、OpenAI、Codex、Cursor、Gemini 等 AI 工具的配置。偷到 npm token 后,它会枚举该账号能发布的包,注入同一套钩子、抬高版本号,再通过 npm 发布出去。

Socket 在 keyv 6.0.0 中识别出的恶意载荷
它还把启动入口写进 .claude/settings.json 和 .vscode/tasks.json。这意味着开发者或 AI 编程工具只要打开被污染的仓库,就可能触发载荷,不一定非要执行 npm install。控制端地址也没有硬编码在文件里,而是通过以太坊智能合约动态取得,攻击者可以换域名而不用重新发布恶意包。

更麻烦的是“合法签名”没有救场。keyv@6.0.0 带有通过验证的 provenance,因为正常的 GitHub Actions 工作流确实构建了它;问题在于,工作流拿到的源代码已经被污染。签名能证明“是谁、用哪条流水线构建”,不能证明源代码本身安全。

依赖里见过 keyv,现在该怎么做

很多项目没有直接安装 keyv,依赖树里却会绕进去。常见链路是 eslint → file-entry-cache → flat-cache → keyv。Wiz 的客户环境统计里,file-entry-cacheflat-cache 和 keyv 的出现率都在 46% 左右,这也是这次事件扩散得快的原因。

Wiz 统计的受影响包在云与代码环境中的出现率
Wiz 统计的受影响包在云与代码环境中的出现率处置时,先看 lockfile 最终解析到了哪个版本,以及安装脚本有没有在开发机或 CI 上运行。别只搜 package.json,也别直接执行一次 npm update 就当修好了。

建议按这个顺序处理:

  1. 1先隔离,再确认。 暂停相关构建和发布,把命中恶意版本且执行过安装脚本的开发机、Runner 和构建容器视为可能失陷。
  2. 2先拆掉触发器。 检查并清理 .claude/settings.json.vscode/tasks.json~/.local/bin/gh-token-monitor.sh~/.config/gh-token-monitor/,以及 macOS LaunchAgent 或 Linux systemd 用户服务中的同名监控项。
  3. 3再撤销和轮换凭据。 覆盖 npm、GitHub、云平台、Vault、Kubernetes、SSH、Terraform、CI/CD 和本机 AI 工具配置里能被读取的密钥。只改密码不够,已有 token 要主动撤销。
  4. 4从干净环境重建。 锁定到确认安全的版本,重建 lockfile、Runner 和镜像,再审计 8 月 4 日之后出现的异常 npm 发布、GitHub 仓库、提交和工作流。

第二步不能跳。Socket 发现恶意程序会每 60 秒检查被盗 GitHub token 是否仍然有效;一旦收到 4xx,也就是 token 被撤销或轮换,它可能执行远程下发的处理命令。没有事件响应经验的团队,最安全的动作是先断网隔离主机,再让安全人员清除持久化项,不要在生产环境里试着触发它。

是否中招,最终看的是“恶意版本有没有进入 lockfile、安装钩子有没有执行、仓库启动项有没有被写入”。即使 `keyv` 只是间接依赖,也要查;如果确认运行过恶意版本,就按主机失陷处理,而不是只升级一个 npm 包。

转自:https://mp.weixin.qq.com/s/92-tGBDWE6A5ua-ysNZ0LQ