この記事は 2026-05-13 時点の公開情報をもとにしています。Mini Shai-Hulud キャンペーンは追跡中の事案なので、影響パッケージや IOC(Indicator of Compromise: 侵害の痕跡)は更新される可能性があります。

2026 年 5 月、TanStack の npm パッケージ群で supply chain compromise が報告されました。42 個の @tanstack/* パッケージに悪性バージョンが publish され、install 時に credential stealer が実行されるという事案です。

この事件は、TanStack 単体のインシデントとして見ると少し小さく見えます。The Hacker News の記事や StepSecurity、Socket の解析を見ると、実際には Mini Shai-Hulud と呼ばれる自己増殖型 supply chain campaign の一部として捉えたほうがよさそうです。

重要なのは、これは単なる「依存パッケージの侵害」ではなく、開発環境と CI/CD を踏み台にして、次の maintainer、次の package ecosystem へ広がるワームだった、という点です。

TanStackで起きたこと

TanStack 公式 Advisory によると、2026-05-11 19:20 から 19:26 UTC ごろに、42 個の @tanstack/* パッケージで合計 84 個の悪性バージョンが npm registry に publish されました。CVE は CVE-2026-45321、CVSS は 9.6 の critical とされています。

TanStack の publish は、正規の GitHub Actions OIDC trusted-publisher binding 経由で認証されていました。一方で、公式 Advisory は publish workflow 自体は改ざんされていないと説明しています。

この節の TanStack 側の時系列と GitHub Actions の詳細は、TanStack の公式 postmortem と GitHub Advisory をもとにしています。

攻撃の流れを単純化すると、こうなります。

TanStack固有の経路:

pull_request_target内でfork PRのコードをcheckoutしてbuild
  + GitHub Actions cache poisoning
  + Actions runner processからのOIDC token extraction
  -> 正規release workflow経由に見える悪性publish

ここで問題だったのは、pull_request_target を使ったこと自体ではありません。pull_request_target は base repository 側の文脈で動くため、本来はラベル付けやコメント投稿のように、PR の中身を実行しない処理に使うべきものです。

TanStack の postmortem では、bundle-size.ymlpull_request_target で動き、その中で fork PR の merge ref を checkout し、bundle size 計測のために build を実行していたと説明されています。つまり、untrusted な fork PR のコードが、base repository 側の cache scope で実行されていました。これが cache poisoning の入口になりました。

ここで「test workflow と release workflow が似た cache key を使うこと」自体は珍しくありません。たとえば pnpm-lock.yaml の hash を使って pnpm store を cache するのは、CI を速くするためによくある構成です。

問題は、untrusted な fork PR のコードが触れる cache と、release workflow が使う cache が同じ信頼境界に入ってしまったことです。cache は復元された瞬間に勝手に実行されるわけではありません。しかし release workflow の pnpm install や build step が、復元された pnpm store 内の依存や binary を参照すると、そこに仕込まれた攻撃者制御のコードが実行される可能性があります。

同じcache keyを使うこと:
  よくある

untrusted PRが作ったcacheをreleaseが使えること:
  あってはいけない

TanStack の場合、fork PR 側で実行された悪性スクリプトが pnpm store を汚染し、actions/cache の post-job save によってその pnpm store が保存されました。その後、main への push で起動した release workflow が同じ cache を復元し、build/test/cleanup の過程で攻撃者制御の binary が呼ばれ、OIDC token extraction と npm への直接 publish につながりました。

悪性パッケージには、約 2.3 MB の難読化 JavaScript の router_init.js が追加されていました。これは install 時に実行され、AWS IMDS、GCP metadata、Kubernetes service-account token、Vault token、~/.npmrc の npm token、GitHub token、SSH private key などを収集します。

ここまでは「TanStack の release pipeline がどう破られたか」の話に見えます。しかし Mini Shai-Hulud の怖さは、その次にあります。

TanStackだけでない

The Hacker News の記事では、TeamPCP に関連づけられている攻撃として、TanStack だけでなく UiPath、Mistral AI 関連パッケージ、OpenSearch、Guardrails AI などの npm/PyPI パッケージ侵害が挙げられています。

Socket も、TanStack の初期報告後に OpenSearch、PyPI の mistralai@2.4.6、PyPI の guardrails-ai@0.10.1、追加の Squawk 系 npm package などを、この campaign に関連する compromised artifact として追跡しています。

全体像はこうなります。

より広いキャンペーン:

Mini Shai-Hulud
  + credential stealing
  + package maintainer enumeration
  + npm/PyPI横断の感染
  + Claude Code / VS Code / GitHub Actionsへの永続化

攻撃者は credential を盗むだけでなく、maintainer が publish 可能な package を列挙し、感染版を再 publish します。1 つの CI/CD 環境や開発端末の侵害が、別の package ecosystem へ波及する構造になっています。

ワームとしての流れ

Mini Shai-Hulud の挙動を、依存パッケージを install した後の流れとして見るとこうなります。

Compromised package install
侵害されたpackageをinstall

router_init.js / transformers.pyz
悪性payloadの実行

credential theft
credentialの窃取
  ├─ GitHub token
  ├─ npm token
  ├─ cloud credentials
  ├─ SSH keys
  └─ CI secrets

exfiltration
外部送信
  ├─ filev2.getsession.org
  ├─ seed1/2/3.getsession.org
  └─ GitHub GraphQL dead-drop

self-propagation
自己増殖
  ├─ enumerate maintainer packages
  ├─ publish infected versions
  └─ inject workflows / persistence hooks

盗んだデータは filev2.getsession.orgseed1.getsession.org など Session/Oxen 系のインフラへ送信されます。The Hacker News は filev2.getsession.org について、Session Protocol のインフラを使うことで、企業ネットワークでブロックされにくくし検知を避けようとしたものだと説明しています。

さらに fallback として、盗んだ GitHub token を使い、GitHub GraphQL API 経由で攻撃者管理 repository に暗号化データを commit する経路もあります。これは、外部サーバーへ直接送れなかったデータを GitHub 上の repository にいったん置いておく dead-drop のような使い方です。この commit author として claude@users.noreply.github.com が使われる点も IOC になります。

永続化と横展開

一連の流れで特に見るべきなのは、install された瞬間の credential theft だけではありません。報告されている永続化と横展開の範囲が広い点です。

StepSecurity と Socket の解析では、以下のような artifact が挙げられています。

  • .claude/settings.json
  • .claude/router_runtime.js
  • .claude/setup.mjs
  • .vscode/tasks.json
  • .vscode/setup.mjs
  • ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
  • ~/.config/systemd/user/gh-token-monitor.service
  • .github/workflows/codeql_analysis.yml

Claude Code や VS Code の hook に仕込まれると、IDE を開くたびに stealer が再実行されます。gh-token-monitor service は GitHub token を監視し、再送信するための永続化として使われます。

さらに GitHub Actions workflow を repository に注入し、toJSON(secrets) で repository secrets を JSON 化して api.masscan.cloud へ送る variant も報告されています。

CI/CD 側では、StepSecurity が特に重要な挙動を報告しています。悪性 payload は Linux の GitHub Actions runner 上で Runner.Worker process を探し、/proc/<pid>/mem を読んで masked secret を含む workflow secret を抜き取ります。つまり、workflow YAML で明示的に参照していない secret でも、runner process のメモリに存在すれば盗まれる可能性があります。

PyPI側にも広がる

今回の話は npm だけではありません。

Socket は、PyPI の guardrails-ai@0.10.1 について、import 時に悪性コードが実行される点を特に危険視しています。Linux 環境を確認したうえで、git-tanstack.com/transformers.pyz から Python artifact をダウンロードし、/tmp/transformers.pyz に書き込んで python3 で実行します。この挙動は直前の guardrails-ai@0.10.0 には存在しなかったとされています。

The Hacker News は、Microsoft の X 上の解析を引用する形で、mistralai@2.4.6 が remote server から credential stealer を取得する挙動や、ロシア語環境を避けるロジック、特定地域に見える場合の破壊的分岐を取り上げています。

npm の lifecycle script だけを警戒していても足りません。Python package の import、CI 上の install、開発端末の IDE hook まで含めて見る必要があります。

SLSA provenanceも安心材料にならず

この攻撃の厄介な点は、悪性 package が正規の GitHub Actions OIDC trusted publishing を使って publish され、有効な SLSA provenance を持っていたことです。

provenance は「どの pipeline が artifact を作ったか」を示します。しかし「その pipeline が攻撃者コードに汚染されていなかったか」までは保証しません。

今回の攻撃では、信頼された pipeline そのものが攻撃者の publish 経路になりました。だから provenance badge や Sigstore attestation だけを見て「安全」と判断するのは危険です。

初動対応

影響を受けた可能性がある端末や runner で、まずやるべきことは「lockfile を戻す」だけではありません。ただし、ここでは手順書として細かく書き切るより、公式 Advisory と専門ベンダーの解析を見ながら対応するほうが安全です。

TanStack 公式 Advisory は、影響バージョンを install した開発端末や CI 環境を compromised とみなし、install process からアクセス可能だった credential の rotation、cloud audit log の確認、CI pipeline の監査を推奨しています。

詳しい対応は、まず次を確認するのがよいです。

実務上は、少なくとも次の領域を確認します。

  • 影響端末や runner の隔離
  • GitHub PAT、npm token、cloud credential、Vault token、Kubernetes token、SSH key の rotation
  • GitHub Actions secrets と environment secrets の rotation
  • npm publish log と GitHub repository の不審な変更確認
  • .claude/.vscode/、LaunchAgent、systemd user service などの永続化確認
  • filev2.getsession.orgseed*.getsession.orgapi.masscan.cloud への egress 調査

StepSecurity は、npm token に IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner という description がある場合、破壊的挙動の可能性があるため、隔離や保全の前に安易に revoke しないよう注意しています。token rotation は感染が疑われる端末ではなく、clean machine から、組織の incident response 手順に沿って進めるべきです。

再発防止として見るべきところ

今回の教訓は、pull_request_target を使うかどうかだけではありません。

  • untrusted PR と release pipeline の cache を共有しない
  • pull_request_target では untrusted code を checkout して実行しない
  • publish job だけに id-token: write を付与
  • それ以外の workflow は permissions: id-token: none を明示
  • release 用 workflow と通常の test workflow を分離
  • third-party action は tag ではなく commit SHA で pin
  • self-hosted runner や long-lived runner に secret を残さない
  • lockfile と frozen install の徹底
  • 依存更新への minimum release age の導入

pnpm なら、pnpm-workspace.yamlminimumReleaseAge を設定できます。たとえば 7 日遅延なら 10080 分です。pnpm 11 系では、明示的に厳格化するなら minimumReleaseAgeStrict も設定します。

minimumReleaseAge: 10080
minimumReleaseAgeStrict: true

これは万能ではありません。すでに lockfile に入っている悪性バージョンや、明示的に指定した悪性バージョンを自動で無害化するものではありません。それでも、公開直後の malicious release を即時に拾うリスクを下げる層としては有効です。

まとめ

TanStack の事件は、pull_request_target の設定ミスだけで説明すると小さく見えます。

しかし実態は、CI/CD、cache、OIDC、npm trusted publishing、IDE hooks、GitHub Actions secrets、PyPI までをまたぐ自己増殖型ワームの一部でした。攻撃者は package を汚染するだけでなく、開発者と CI 環境を踏み台にして、次の maintainer、次の package へ広がる仕組みを持っていました。

だから対策も、lockfile 確認だけでは足りません。見るべき対象は、依存関係、開発端末、GitHub repository、CI/CD runner、secret 管理、publish 権限の全体です。

Mini Shai-Hulud は、「依存パッケージの侵害」ではなく「開発環境と CI/CD の侵害」という大きな問題となっています。

参考


この記事は Zenn にも転載しています。