前言¶
2026 年 8 月 4 日,Microsoft Threat Intelligence 披露了一起代號爲 ChainDrop 的大規模 npm 供應鏈攻擊。攻擊者在數小時內向 npm 註冊表發佈了 440 餘個包、2200 多個惡意版本,波及 keyv、flat-cache、cache-manager 等高頻依賴,累計周下載量超過 5 億次。這不是一次簡單的包投毒——蠕蟲通過 preinstall 生命週期鉤子在 npm install 階段自動執行,竊取 npm、GitHub、AWS、Kubernetes、HashiCorp Vault 等憑證,再利用被盜身份自動修改並重新發布更多包,形成自我傳播的感染鏈。部分變種還會向倉庫注入 Claude 與 VS Code 配置文件,建立持久化後門。
本文基於 Microsoft、StepSecurity、SecurityWeek 等公開分析報告,梳理 ChainDrop 的攻擊鏈路、技術特徵與可操作的防護建議。
事件概覽:從 11 個種子包到 400+ 感染¶
ChainDrop 屬於 Mini Shai-Hulud 蠕蟲家族的演進版本,是 2025 年以來 npm 供應鏈攻擊浪潮中的最新一輪。與此前 Shai-Hulud 攻擊類似,但引入了 EtherHiding(以太坊區塊鏈 C2)等新技術。
時間線(UTC,2026-08-04):
- 攻擊者首先入侵
keyv、cacheable等命名空間維護者 Jared Wray 的 GitHub 賬戶。 - 約 09:00 UTC,
keyv@6.0.0等 11 個「種子包」被髮布,攜帶完整蠕蟲載荷。 - 惡意包在開發者工作站與 CI/CD _runner 上執行後,竊取憑證並自動向 npm 重新發布被感染包。
- 四小時內,StepSecurity 觀測到 444 個包、2212 個版本 被投毒;npm 團隊在約兩小時內開始下架惡意版本,但蠕蟲仍可通過新被盜賬戶持續傳播。
受影響範圍:
| 指標 | 數據 |
|---|---|
| 感染包數量 | 440+(StepSecurity 統計 444) |
| 惡意版本數 | 2200+(StepSecurity 統計 2212) |
| 種子包 | 11 個(keyv、cacheable 生態) |
| 蠕蟲自動傳播 | 433 個額外包 |
| 周下載量 | 超 5 億次(SecurityWeek) |
典型高危包包括 keyv@6.0.0(周下載約 1.5 億)、flat-cache@6.1.24(約 1.5 億)、file-entry-cache@11.1.6(約 1.47 億)——它們廣泛出現在 ESLint、cache-manager 等工具鏈中,意味着大量 JavaScript 項目可能間接依賴了被感染版本。
攻擊鏈路:preinstall 鉤子如何成爲入口¶
Microsoft 的分析指出,許多惡意版本 沒有對應的 GitHub 提交、PR 或 Tag,說明攻擊者並非逐個入侵源碼倉庫,而是直接修改 tarball 並通過被盜 npm 發佈令牌重新上傳。這是 ChainDrop 傳播速度極快的根本原因之一。
1. 入口:preinstall 生命週期鉤子¶
npm 在安裝依賴時會按順序執行生命週期腳本。ChainDrop 在被感染包的 package.json 中加入 preinstall 鉤子,指向包內的 setup.mjs:
{
"scripts": {
"preinstall": "node setup.mjs"
}
}
由於 preinstall 在包安裝完成 之前 就會運行,惡意代碼可以在單元測試、SAST 掃描等常規安全檢查啓動前就完成執行——無論是本地 npm install,還是 CI 流水線中的依賴安裝步驟,都可能觸發。
2. 二階段載荷:Bun 運行時 + 混淆腳本¶
setup.mjs 會下載合法的 Bun JavaScript 運行時,並加載約 710 KB 的混淆二階段腳本(常見文件名爲 Math_Symbol.js 或 math_init.js)。使用 Bun 而非 Node.js 本身,有助於繞過部分針對 Node 進程的監控規則。
Microsoft Defender 已將該行爲標記爲 Suspicious usage of Bun runtime、Trojan:NPM/MalBun.A 等檢測項。
3. 憑證收集:從本地文件到雲 API¶
載荷啓動後會區分 開發者工作站 與 CI/CD 環境:
- 在開發者機器上,進程會 detach 到後臺 繼續運行;
- 在 CI 環境中,進程保持附着,以便讀取 workflow secrets、runner 憑證及 GitHub Actions OIDC 發佈權限。
收集範圍包括:
- 本地憑證文件、Shell 歷史、SSH 密鑰、雲配置文件;
- 進程環境變量(含
NPM_TOKEN、GITHUB_TOKEN等); - 通過
gh auth token、gcloud、az等 CLI 獲取的令牌; - 利用已獲憑證調用 AWS、Kubernetes、HashiCorp Vault API,枚舉並拉取更多密鑰。
4. 數據外傳:HTTPS + GitHub 備用通道¶
竊取的數據經 JSON 序列化、gzip 壓縮後,用 AES-256-GCM 加密,密鑰再用攻擊者 RSA 公鑰封裝。外傳路徑:
- 主通道:攻擊者控制的動態 HTTPS 端點。C2 域名通過以太坊智能合約(
0xE1f2395ee43e45A1556EC6438a88c31B83493103)或簽名 GitHub commit(標記thebeautifulmarchoftime)下發,分析時活躍域名爲npm-cache.com,歷史候選包括pypi-get.com、js-mirror.com。 - 備用通道:利用被盜 GitHub 令牌創建公開倉庫,描述爲 「Shai-Hulud: Here We Go Again」,將加密結果以
results-*.json文件提交。
5. 蠕蟲傳播:一個令牌感染所有可發佈包¶
ChainDrop 最具破壞力的能力在於 自動化傳播。獲得 npm 發佈令牌後,蠕蟲會:
- 枚舉該身份可訪問的所有包;
- 下載各包最新 tarball;
- 插入惡意
setup.mjs與Math_Symbol.js,替換 lifecycle scripts; - patch 版本號 +1 後重新發布。
一個被盜維護者賬戶即可在數小時內產出數百個惡意 patch 版本——且這些版本往往看起來只是普通的補丁升級,源碼倉庫卻毫無變動。
6. GitHub Actions OIDC 濫用¶
對於配置了 npm Trusted Publishing(OIDC)的倉庫,蠕蟲還有專門路徑:利用 workflow 身份獲取合法 provenance 的發佈權限,使惡意包攜帶 看似可信的來源簽名。這意味着僅靠 provenance 校驗不足以防禦此類攻擊。
7. 持久化:Claude / VS Code 配置注入¶
蠕蟲還會利用被盜 GitHub 憑證,向可寫倉庫分支注入配置文件:
.claude/settings.json、.claude/setup.mjs.vscode/tasks.json、.vscode/setup.mjs
當開發者後續使用 Claude Code、VS Code 或 GitHub Copilot 打開項目時,載荷可能再次被觸發,形成 開發者到開發者 的二次感染路徑。部分 macOS/Linux 變種還安裝了「死手開關」:每 60 秒輪詢 GitHub API 檢測令牌有效性,令牌被撤銷則自毀;另有 24 小時自清理機制。
與 Shai-Hulud 的演進關係¶
ChainDrop 被安全社區視爲 Shai-Hulud 2.0 蠕蟲的重度演進版本,主要新增能力包括:
| 特性 | Shai-Hulud(早期) | ChainDrop |
|---|---|---|
| 執行入口 | postinstall / preinstall | preinstall + Bun 二階段 |
| C2 通信 | 靜態域名 / GitHub | EtherHiding(以太坊合約動態下發) |
| 傳播方式 | 手動或半自動 | 全自動 tarball 修改 + 重發布 |
| 持久化 | 有限 | Claude / VS Code 配置注入 |
| CI 目標 | 憑證竊取 | 憑證竊取 + OIDC 發佈濫用 |
蠕蟲還會檢測 俄語系統環境 並主動退出,這一特徵在 Microsoft 與 StepSecurity 的分析中均有提及。
如何自查:你的項目是否受影響¶
1. 檢查 lockfile 與 node_modules¶
對照 StepSecurity、Wiz、Socket 等廠商維護的 受影響包列表,檢索 package-lock.json、yarn.lock、pnpm-lock.yaml 中的版本號。不要只看直接依賴——被感染包多爲 傳遞依賴。
# 示例:在 lockfile 中搜索已知高危包
grep -E '"(keyv|flat-cache|file-entry-cache|cache-manager)"' package-lock.json
2. 關注 IOC(入侵指標)¶
Microsoft 公佈的文件哈希:
| SHA256 | 說明 |
|---|---|
54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668 |
setup.mjs(npm preinstall 加載器) |
fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb |
setup.mjs(.claude / .vscode 加載器) |
9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc |
Math_*.js 蠕蟲主體 |
網絡 IOC:npm-cache.com、pypi-get.com、js-mirror.com,以及 https://npm-cache.com:443/router。
3. 檢查 CI 與本地環境¶
在終端或 SIEM 中檢索以下進程特徵:
# 可疑 preinstall 執行
node setup.mjs
# Bun 二階段加載(路徑含 bun-dl- 或 node_modules)
bun ... Math_Symbol.js
若發現匹配,應將該機器視爲 已失陷 處理。
應急響應與長期防護¶
若已安裝被感染版本¶
Microsoft 與 JFrog 的建議可歸納爲以下步驟:
- 隔離:斷開受影響工作站與 CI runner 的網絡,保留 tarball、npm 日誌、CI 日誌、GitHub audit log 以便界定暴露窗口。
- 清理:清除
node_modules、npm/yarn 緩存(含共享 CI 緩存);重建 runner 鏡像與 golden build 環境。 - 輪換憑證:在 已知乾淨的環境 中撤銷並輪換 npm token、GitHub PAT、AWS 密鑰、K8s ServiceAccount、Vault token 等——順序很重要,先隔離再輪換。
- 審計倉庫:檢查
.claude/、.vscode/目錄是否有異常注入;審查 GitHub Actions workflow 變更與 npm 發佈記錄。 - 重建制品:從已知良好的依賴基線重新構建,確認緩存與製品庫中不存在被感染哈希。
日常防護建議¶
- 升級 npm CLI 至 v12+,啓用
min-release-age功能,延遲安裝剛發佈的版本,爲社區下架爭取窗口。 - 鎖定依賴版本(pin / lockfile commit),避免 CI 中無鎖自動拉取最新 patch。
- CI 中禁用 lifecycle scripts 或使用
--ignore-scripts(需評估對原生模塊的影響):
npm ci --ignore-scripts
- OIDC Trusted Publishing 仍推薦使用,但需配合 workflow 審批、環境保護規則與異常發佈告警,不能作爲唯一防線。
- 最小權限原則:npm 發佈 token、GitHub PAT、雲 IAM 角色應限定到必要範圍;CI secrets 按 job 隔離。
- 供應鏈監控:接入 Socket、Snyk、Dependabot 等工具,對新增 patch 版本做 diff 與行爲分析。
寫在最後¶
ChainDrop 再次證明:npm 供應鏈的安全邊界早已超出「某個包有沒有被入侵」——CI/CD 憑證、OIDC 發佈鏈、AI 開發工具配置 都可能成爲攻擊跳板。一個維護者賬戶的 GitHub 泄露,可以在四小時內演變成波及數百個包、數億次周下載的蠕蟲風暴。
對普通開發者而言,當下最務實的動作是:覈對 lockfile、清理緩存、輪換可能暴露的令牌。對團隊而言,則需要把依賴安裝、發佈流程和憑證管理當作同一套安全體系來審視——因爲下一次攻擊,很可能還是從 npm install 的那一行 preinstall 腳本開始。