摘要: StepSecurity 於 2026 年 5 月 11 日追蹤到 npm 供應鏈蠕蟲 Mini Shai-Hulud,指向 TeamPCP,受害套件超過 170 個,包含 Mistral SDK。攻擊者竊取維護者 CI/CD 憑證後自動推送感染版本,上架時附帶密碼學上有效的 SLSA 證明。payload 竊取 OIDC 權杖、雲端憑證與 agent 設定,並在開發者工具建立持久化。
2026 年 5 月 11 日,一隻具備自我複製能力的供應鏈蠕蟲 Mini Shai-Hulud 在 npm 生態系現蹤。StepSecurity 把幕後黑手指向 TeamPCP,手法是先竊取維護者的憑證,再自動為其名下所有套件推送受感染版本。TanStack 已證實共有 42 個 @tanstack/* 套件被塞入 84 個惡意版本,整波疫情擴及 170 多個套件。
整起事件最令人不安的一點在於:這些惡意套件上架時竟附帶密碼學上有效的 SLSA 證明——因為蠕蟲奪走的,正是各專案自己的發布管線。
從單一 fork 蔓延到 170 多個套件
這個攻擊帳號 3 月現身之後一直按兵不動,直到 5 月 10 日 fork 了 TanStack/router、把 payload 藏進其中;11 日,帶毒版本接連上架,react-router 1.169.5 與 1.169.8 皆在其列,隨後一路擴散至 opensearch、UiPath、safe-action 等。
Mistral 的狀況是由官方 repo 自己揭發的:mistralai/client-ts 的 issue #217 指出 @mistralai/mistralai 2.2.4 遭到植入;受影響範圍為 2.2.3 與 2.2.4,azure/gcp 變體與 PyPI 側同樣中鏢。
想稽核植入痕跡並不難:每個被汙染的 tarball 會多出一條 optionalDependencies,並夾帶一個 2.3 MB、經三層混淆的 router_init.js,整個 tarball 的體積於是從 190 KB 膨脹到 905 KB。
鎖定 AI 開發環境的竊密手法
看看 payload 的目標,就知道它是衝著 AI 開發環境來的:它從 /proc 的程序記憶體挖出 GitHub Actions 的 Runner.Worker,奪走 OIDC 權杖,連 AWS IMDSv2、ECS 與 Vault 憑證也不放過;掃描範圍涵蓋 100 多條路徑,從雲端金鑰一路找到 Claude、Kiro 的設定檔。它同時在 Claude Code 與 VS Code 裡建立持久化,並藉偽裝的 workflow 把整個 repo 的機密一口氣倒出;為了避開針對 Node.js 的工具,它改用 Bun 1.3.13 執行,外傳管道則是 Session CDN 與 GitHub dead-drop commit,作者欄的郵址偽裝成 claude@users.noreply.github.com。
有效的 SLSA 證明為何救不了這一次
Red Hat 的 Andrew McNamara 事後在 SLSA 部落格把整條攻擊路徑拆解成三步:pull_request_target 使來自 fork 的程式碼得以在受信任環境中執行;惡意程式趁機汙染 pnpm 共享快取,而正規的 release workflow 隨後又把這份快取還原回來;最後攻擊者撈出 OIDC 權杖,直接把套件推上 npm。
答案相當殘酷:簽章無誤,不代表內容可信。npm 內建的 provenance 只達 Build L2,這次攻擊卻一口氣擊穿 L3 的全部三項隔離要求——共享快取遭汙染、簽署身分外洩、攻擊程式碼在建置之間存活。兩次惡意 CI run 都以 failure 作收,套件卻照樣完成發布——針對這種情況設下告警,就能縮短暴露窗。
蠕蟲式擴散與撤銷憑證的陷阱
這隻蠕蟲專挑帶有 bypass_2fa 的 npm token 下手,接著枚舉該維護者名下的所有套件,逐一發布受感染版本。更陰險的是,其中一個 token 的描述直接寫著「撤銷這個 token 將抹除擁有者的電腦」——應先隔離取證、再輪換憑證,貿然 revoke 反而可能觸發破壞性清除。
事件後的處置與修補
只要裝過任何受害版本,就該把該環境的機密視為已全數外洩:先退回乾淨版本,刪除 node_modules 後重裝,接著輪換 npm token、PAT、雲端金鑰與 SSH key,並回頭稽查 11 日 19:20 UTC 之後的 CI。結構面的修補包括:替 pull_request_target 加上閘控、落實最小權限、以 digest 釘選 action,並把共享快取當成信任邊界看待。agent 設定檔也應當作機密保管;要部署 coding agent 的話,沙箱與審批就是下一道防線(見OpenAI 安全部署 Codex)。
