2026 年 8 月 4 日,npm 注册中心爆发代号”Shai-Hulud”(沙丘蠕虫)的供应链攻击。新一轮蠕虫从 keyv 维护者遭劫持的 GitHub 账号出发,借助 preinstall 生命周期钩子、自带 Bun 运行时与 IDE 自动触发文件,在约 30 分钟内向 keyv、cacheable、flat-cache、file-entry-cache、cacheable-request、cache-manager 等数十个流行包注入后门,并通过 npm 自动化令牌自传播至下游。截至 8 月 4 日傍晚,Aikido 与 JFrog 等监测机构已确认至少 868 个 npm 包(1381 个版本)被污染,合计月下载量约 20 亿次。受影响的二级维护者名单已经扩散至 @deliveroo/reevent、@picsart/ai-sdk、@qlik/embed-runtime、@or-sdk/invitations、picasso.js 等知名组织。
事件概述
keyv 是 Node 生态中最流行的键值抽象层之一,单包每周下载约 1.27 亿次,同时是 ESLint 等工具的传递依赖。该项目维护者同时维护 cacheable、cacheable-request、flat-cache、file-entry-cache 等高频使用的缓存工具。攻击者接管维护者 GitHub 账号后,使用合法凭据将恶意提交推送到 main 分支,并立即触发包含 GitHub Actions 合法 provenance 的版本发布,污染包因此带有官方签名。
主要被注入的两个文件是 setup.mjs 与 Math_Symbol.js,package.json 中追加 "preinstall": "node setup.mjs"。当用户执行 npm install 时,setup.mjs 作为轻量级 loader 静默下载 Bun 1.3.13 独立运行时,并用它执行 728 KB 的混淆主载荷 Math_Symbol.js,借此规避宿主 Node 的 hook 检测与常见审计工具。
技术细节
1. 凭据收割与多通道外泄
蠕虫在受感染主机上执行下列典型作业:
- 扫描
.npmrc与本地缓存,提取npm自动化令牌,并实时调用registry.npmjs.org/-/whoami校验可用性; - 抓取 GitHub PAT、OAuth Token、OIDC JWT(含 Actions runner 内存中的发布用 ID Token);
- 遍历 AWS、GCP、Azure、EC2/ECS 元数据、Vault、Kubernetes ServiceAccount Token、Stripe、Slack、SSH 私钥、加密货币钱包等 200 余种凭据模式;
- 将结果加密后投递至攻击者创建的 GitHub 仓库(描述统一为 “Shai-Hulud: Here We Go Again”)以及硬编码 HTTPS / DNS 信道。
2. 自传播逻辑
蠕虫在拿到可用 npm 令牌后,对该身份可写的每一个包执行”劫持-加壳-提版本-发布”:下载原始 tarball、复制恶意样本至 package/math_init.js、覆盖 scripts.preinstall、递增 patch 版本号,并直接以 PUT 方式推送到 npm registry。借力 npm 12+ 的 OIDC trusted publishing,单次凭据失陷即可在数分钟内扩散至数百包。
3. IDE 与 AI 编码代理反触发
蠕虫还会在目标 GitHub 仓库的 main 分支中植入 .vscode/tasks.json、.vscode/setup.mjs、.claude/settings.json、.claude/math_init.js、.claude/setup.mjs 五份文件,绕过 npm 安装阶段直接被触发:
.vscode/tasks.json在 VS Code 打开文件夹时执行node .claude/setup.mjs;.claude/settings.json在 Claude Code 启动会话时通过 SessionStart hook 执行node .vscode/setup.mjs。
这意味着即便使用 --ignore-scripts 或升级到 npm 12,只要开发者或 AI 代理打开含毒的仓库目录,载荷仍会自动执行。
4. 对 GitHub Actions 的二次偷凭
针对含有 workflow 权限的 GitHub Token,蠕虫会枚举 9 月份以来该身份可推送的仓库,针对其中任意一个创建 dependabot/github_actions/format/setup-formatter 分支,注入一个名为 Run Copilot 的 workflow,将 ${{ toJSON(secrets) }} 序列化到工件 format-results.txt 中以供下载。
影响评估
该事件已进入”生态系统级”供应链事故级别:keyv@6.0.0(约 6.04 亿次月下载)、flat-cache@6.1.24(5.80 亿)、file-entry-cache@11.1.6(5.71 亿)以及 cacheable-request@13.0.20(1.37 亿)等包几乎覆盖了所有 Node 项目。攻击者只要劫持一个维护者,就能沿信任图谱跨多家公司连锁扩散;常见依赖审计只盯 namespace 白名单,无法发现被劫持的合法发布,因而无法及时阻断。
主载荷的 SHA-256 已公开为 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc,微软 Defender 已为其标记 Trojan:npm/MalBun.A。由于依赖树太深,绝大多数受害团队甚至不会意识到自己引入了被劫持的包;这也意味着公开 PoC 与外泄基础设施在过去 24 小时内已被纳入多个主流勒索软件集团的工具库。
修复建议
- 立即将 keyv 锁回
5.6.0,并核实所有依赖图中是否存在keyv@6.0.0、flat-cache@6.1.24、file-entry-cache@11.1.6、cacheable-request@13.0.20、cacheable@2.5.1、@cacheable/memory@2.2.1、cache-manager@7.2.10、@cacheable/node-cache@3.1.2、@cacheable/utils@2.5.1、@cacheable/net@2.1.1、ecto@5.0.1; - 对 8 月 4 日 09:39 UTC 之后的任何
main分支发布视为不可信,审阅近期由维护者发起的版本并比对 SHA-256; - 在轮换凭据前先移除
claude/settings.json、.vscode/tasks.json、setup.mjs中可能存在的 token-revocation watcher; - 立即回收所有可能暴露的 npm 自动化令牌、GitHub PAT、GitHub App、AWS/GCP/Azure/Vault/Kubernetes/SSH/Stripe/Slack 凭据,并清理 8 月 4 日前后构建的 CI runner;
- 升级到 npm 12+ 以默认阻止未审批的 preinstall;但需注意 IDE hook 路径仍然有效,建议在 IDE 与 AI 代理中显式禁用未受信任目录的自动任务;
- 启用 npm 的 OIDC trusted publishing 时增加人工审批环节,避免被盗令牌沉默发布;
- 在仓库监控规则中追加:包版本新增/修改 preinstall / postinstall / prepare、运行时进程连接
github.com/oven-sh/bun或任何非 npm 注册端点、出现.claude、.vscode、setup.mjs异常工件,以及描述为 “Shai-Hulud: Here We Go Again” 的可疑仓库。
参考来源
- JFrog Security Research:Major Shai Hulud campaign strikes npm again, affecting keyv and 400+ packages
- Aikido Security:keyv and friends compromised in active Shai-Hulud supply chain attack
- OX Security:A Massive Shai-Hulud Campaign Hits npm: 440+ Packages Compromised, Over 2B Monthly Downloads
- The Hacker News:Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks
- CyberPress 综述:Shai-Hulud npm Worm Compromises 868 Packages With Over 2 Billion Monthly Installs
- GitHub PoC / IOC:Exploit 参考实现与 IOC 索引(关联样本)