i am Roger Li

開發者注意:keyv / cacheable 供應鏈 worm「Shai-Hulud: Here We Go Again」

前幾日喺 GitHub 同 X 上面見到好多人講一單 npm supply chain攻擊,最初我以為又係普通 typosquatting,點知越睇越覺得唔對路,今次唔係邊緣 package,係直插 JavaScript 生態系最底層嘅 keyv 同佢嘅 cacheable 家族。呢幾日我睇咗幾份報告,包括 Lidor Machluf / Upwind Security 喺 cacheable repo 嘅詳細分析OpenSSF Malicious Packages 嘅Filing同埋 Socket / Aikido / SafeDep 嘅公開報道,呢度同大家整理吓我見到嘅

什麼是 Keyv?為何它的淪陷是一場生態系災難?

keyv 本身係一個喺 Node.js 生態系極受歡迎嘅輕量級Key-Value 儲存介面,佢提供統一 API,俾開發者可以無縫喺 Redis、MongoDB、PostgreSQL 或本機記憶體之間切換快取策略。但 keyv 絕唔係普通 npm 套件,佢同 flat-cachefile-entry-cachecacheablecacheable-requestcache-manager 等一齊,構成咗 JavaScript 開發工具鏈嘅 "底層基礎設施"。

呢啲套件每週下載量合計超過 5 億次(單係 keyvflat-cache 已經過億),而且係 ESLint 呢啲核心工具嘅隱性依賴。佢哋處於無數企業專案 dependency tree 嘅極深處。當攻擊者奪取 maintainer 帳號並落毒,唔係單一專案受害,而係成個生態系嘅 "水源頭" 被落毒。

今次攻擊係幾時發生,對象係乜嘢

事件係 2026-08-04 UTC 早上 爆發。攻擊者入侵咗 jaredwray 嘅 GitHub 帳號(即 keyvcacheable 嘅 maintainer),透過 GitHub Actions OIDC 發布咗以下 10 個受污染版本,全部加咗 "preinstall": "node setup.mjs"

套件 有毒版本 上一個乾淨版本 每週下載
keyv 6.0.0 5.6.0 / 6.0.0-rc.1 ~154M
flat-cache 6.1.24 6.1.23 ~150M
file-entry-cache 11.1.6 11.1.5 ~148M
cacheable 2.5.1 2.5.0 ~8M
cacheable-request 13.0.20 13.0.19 ~34M
cache-manager 7.2.10 7.2.9 ~4M
@cacheable/net 2.1.1 2.1.0
@cacheable/node-cache 3.1.2 3.1.1 ~2M
@cacheable/memory 2.2.1 2.2.0 ~7M
@cacheable/utils 2.5.1 2.5.0 ~9M

之後攻擊利用偷到嘅 npm / GitHub token 繼續自我複製,總共波及 444 個 packages / 2,234 個 versions(OpenSSF 數字),橫跨多個 npm namespace。

發生咩事,嚴重性係點樣

執行流程簡化嚟講係咁:

  1. npm install 觸發 preinstall → 跑 setup.mjs
  2. setup.mjs 下載 / 執行 Math_Symbol.js(一個用 Bun 編譯嘅 CJS payload)
  3. Payload 會偷 npm token、GitHub token、AWS / GCP / Azure / Stripe key、DB connection string、私鑰、CI secrets 等等
  4. 用偷到嘅 token 再發布更多惡意版本,形成 worm

最得人驚嘅幾點:

  • 無固定 C2:exfiltration 經 GitHub dead-drop repositories 同 DNS 進行,傳統 URL reputation 防禦察覺唔到。
  • Dead-man's switch:payload 會裝一個 gh-token-monitor 程序,每隔 60 秒用偷到嘅 token 打 api.github.com/user。一旦你 revoke 咗個 token,佢偵測到 40x 就會觸發額外 handler。所以直接 rotate token 反而可能引爆下一步。
  • CI memory scraping:針對 GitHub Actions Runner.Worker 程序讀 /proc/<pid>/mem,log masking 擋唔到。
  • 開 repo 都中:repo 本身被種咗 .claude/settings.json.vscode/tasks.json,喺 VS Code 開 folder 或 AI agent 啟動 session 都會觸發執行——唔使 npm install。

呢次唔係「改個 function 偷啲 data」咁簡單,係針對整條 CI/CD 同開發者工作流嘅持續性攻擊。

中小企需唔需要理會

老實講,只要有用 Node.js / npm,就一定要理會。 原因好簡單:

  • 你未必直接裝 keyv,但 ESLint、Prettier 周邊工具、Next.js / Nuxt / Vite 生態、各種 CLI 都會間接引進 flat-cache / file-entry-cache
  • 只要任何一個開發者或 CI 喺 8 月 4 日之後 npm install 過,就有可能被執行咗 preinstall hook。
  • 中小企通常冇專職 security team,一個中招可能就洩露咗整個 GitHub / npm / AWS 憑證,後果可以好大。

如果你完全冇用 Node.js,影響就相對間接,但係開發團隊若有使用相關工具,都要提醒佢哋檢查。

有冇簡易方法檢查自己系統有冇受影響

以下係我會做嘅幾步,最快 5 分鐘可以知道大約情況:

1. 檢查 package.json / lockfile 有冇中標版本

# npm
npm ls keyv flat-cache file-entry-cache cacheable cacheable-request cache-manager @cacheable/net @cacheable/node-cache @cacheable/memory @cacheable/utils

# 直接 grep lockfile
grep -E "keyv@6\.0\.0|flat-cache@6\.1\.24|file-entry-cache@11\.1\.6|cacheable@2\.5\.1|cacheable-request@13\.0\.20|cache-manager@7\.2\.10" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

2. 檢查 persistence 同惡意檔案

# dead-man's switch 可能留下的檔案
ls -la ~/.config/gh-token-monitor/ ~/.local/bin/gh-token-monitor.sh ~/Library/LaunchAgents/com.user.gh-token-monitor.plist ~/.config/systemd/user/gh-token-monitor.service 2>/dev/null

# 可疑 process
ps aux | grep -E "gh-token-monitor|bun_environment|Math_Symbol|setup_bun" | grep -v grep

# 被植入的 IDE / agent 設定
find ~ -maxdepth 6 \( -path "*/.claude/settings.json" -o -path "*/.vscode/tasks.json" \) -newer "2026-08-01" 2>/dev/null | xargs grep -l "setup.mjs\|math_init" 2>/dev/null

3. 用 npm audit / SCA 工具

npm audit

或者用 Snyk、Socket、GitHub Dependabot alerts 掃描。OpenSSF Malicious Packages 已經收錄咗呢次事件,支援 OSV 嘅工具會報出嚟。

4. 檢查 GitHub repos 有冇被加入可疑 workflow

# 用 gh CLI 列出自己嘅 repos,搵 "Shai-Hulud: Here We Go Again" 描述
gh repo list --json name,description | grep -i "hulud"

# 搵可疑 workflow
find . -path "*/.github/workflows/*" -name "*.yml" -o -name "*.yaml" | xargs grep -l "toJSON(secrets)\|Run Copilot" 2>/dev/null

可唔可以利用 AI Agent 幫手檢測甚至修復受影響系統

呢個問題我覺得最有趣,因為本身呢次攻擊都有針對 AI agent 嘅 hook(.claude/settings.jsonSessionStart)。所以結論係:可以,但一定要識用。

AI Agent 適合做嘅嘢

  1. 大規模掃描 lockfile:比人眼快好多,可以一次過檢查幾十個 repo 有冇中標版本。
  2. 產生 remediation PR:自動 pin 返去乾淨版本、開 PR、更新 package.json 同 lockfile。
  3. 協助寫 incident response runbook:整理檢查清單、輪轉憑證步驟。
  4. 分析 CI logs / artifacts:搵 format-results.txt 等可疑檔名。

使用 AI Agent 嘅風險

  • 唔好直接叫 agent 打開受影響 repo 做分析:如果 .claude/settings.json.vscode/tasks.json 被植入,agent session 一啟動就可能觸發 payload。
  • 先隔離後掃描:用 Docker、乾淨 VM 或者 --ignore-scripts 環境,先確認 repo 冇毒先俾 agent 處理。
  • agent 睇唔到所有東西:例如 dead-man's switch 喺系統層面,agent 可能冇權限或冇 context 發現。

我會用嘅 workflow

1. 人類先用上文的 5 分鐘檢查做第一輪篩選。
2. 若懷疑 repo 乾淨,才用 AI agent 掃描 lockfile 並產生 pin-version PR。
3. 若發現任何 persistence 檔案,人類處理(或懂安全的 agent 在隔離環境處理)。
4. 修復後再 rotate 所有相關 token——次序好重要,先清 malware 再 rotate。

以下係一個可以餵畀 AI agent 嘅 prompt 範例:

Scan all package-lock.json, yarn.lock, and pnpm-lock.yaml files under /path/to/projects. Report any occurrence of these compromised versions: keyv@6.0.0, flat-cache@6.1.24, file-entry-cache@11.1.6, cacheable@2.5.1, cacheable-request@13.0.20, cache-manager@7.2.10, @cacheable/net@2.1.1, @cacheable/node-cache@3.1.2, @cacheable/memory@2.2.1, @cacheable/utils@2.5.1. Do not run any install scripts. If found, generate a summary table with package, version, project path, and parent dependency chain.

我會點做總結

呢次事件再次證明咗供應鏈安全唔係大廠專利,中小企一樣要面對。最實際嘅幾件事:

  1. 立即檢查 lockfile,睇下有冇中標版本。
  2. --ignore-scripts 做新 install,阻止 preinstall hook 執行。
  3. 先清 malware / persistence 再 rotate token,唔好顛倒次序。
  4. 長遠啲:pin exact versions、用 min-release-age(例如 npm 嘅 npm config set min-release-age=7)、啟用 Dependabot / Snyk / Socket、分拆 CI secrets。

最後一句:開源生態嘅信任鏈真係好脆弱,我哋每個用 npm 嘅人都係鏈上嘅一環。保持警覺,但唔好驚到唔敢寫 code——做足基本檢查,大部分風險都可以控得住。😄


參考來源:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *