Mini Shai-Huludが@antvへ拡散、依存を戻してもClaude Code/VS Codeに痕跡が残る
目次
TL;DR
何が起きた 2026年5月19日UTC、Mini Shai-Huludの新しい波が @antv 系npmパッケージ、echarts-for-react、timeago.js、size-sensor、canvas-nest.js などに広がった。Aikido、SafeDep、The Hacker Newsが同じ波を別の切り口で追っている
TanStack波との差分 payloadの基本は同じだが、今回は依存を戻したあとも開発端末側に起動経路が残ることが明確に出た。Claude Codeの .claude/settings.json SessionStart hookと、VS Codeの .vscode/tasks.json runOn: "folderOpen" タスクがIoCに並ぶ
数字の揺れ SafeDepは atool npmアカウント配下で314パッケージ、637悪意あるバージョン。The Hacker NewsはSocket集計として323パッケージ、639バージョン、うち @antv 279。Aikidoは「hundreds」。同じインシデントを別時点・別scopeで数えた差
対応 node_modules を消す・lockfileを戻す・unpublishしてもClaude CodeとVS Code側に起動経路が残る。gh-token-monitor デーモンが動く前にネットワーク隔離 → .claude/、.vscode/、systemd user service、LaunchAgent、.github/workflows/codeql.yml の追加ぶん除去 → npm、GitHub、AWS、GCP、Kubernetes、Vault、SSH、Docker、DB接続情報の順にローテーション → GitHubアカウント側に逆順マーカー入り公開repoができていないか確認
Mini Shai-Huludが、今度は @antv 系npmパッケージへ広がった。
2026年5月11日のTanStack/Mistral波を追っていた人には、見覚えのある形だ。
正規メンテナ権限を使って悪意あるバージョンを出し、install中にBunでpayload(悪意あるコード本体)を動かし、npmトークンを取れた環境から次のパッケージを再公開する。
ただ、TanStack波と違うところがある。
今回はnpmパッケージを戻したあとも、開発端末側に起動経路が残る。
Claude Codeの SessionStart hookと、VS Codeの folderOpen タスクがIoCに並び、開発者が普段使うエディタとAIツールが永続化先になった。
前回の流れは Mini Shai-HuludがTanStack・Mistralのnpmへ拡大した記事 に書いた。
ソースコード公開とBreachForumsチャレンジを含む話は Shai-HuludワームのGitHub公開記事 側にある。
5/19 UTC、@antvが標的になった
Aikidoは、5月19日UTCに @antv の主要パッケージ群、echarts-for-react、timeago.js、size-sensor、canvas-nest.js などで悪意あるバージョンを検出したと書いている。
@antv/g2、@antv/g6、@antv/x6、@antv/l7、@antv/s2 など、ダッシュボード、グラフ、地図、チャートで使われるライブラリが並ぶ。
Aikidoの一覧には @antv/ のほか、@lint-md/、@openclaw-cn/、@starmind/ といったnamespaceも入っている。
SafeDepは、atool npmアカウントが547パッケージを保守しており、そのうち314パッケージに637件の悪意あるバージョンが出たと整理している。
publishは2回に分かれていて、どちらも2026年5月19日UTC。1回目は01:39〜01:56、2回目は02:05〜02:06。多くのパッケージは2つの悪意あるバージョンを受け取り、size-sensor、echarts-for-react、jest-canvas-mock、jest-date-mock は早期テストのように3バージョン出ている。
The Hacker NewsはSocketなどの集計を引き、639件の悪意あるバージョン、323パッケージ、うち @antv 279パッケージと書いている。
この差は、見ている時点、含めるscope、削除済みバージョンの扱いで変わる数字だ。
314と323のどちらかを正解として読むよりも、自分のlockfileと社内ミラーに残った具体バージョンを直接洗う。
攻撃チェーンはTanStack波とほぼ同じ
入口は、package.json に追加された preinstall だ。
{
"scripts": {
"preinstall": "bun run index.js"
}
}
さらに多くのバージョンで、GitHubのcommitを指す optional dependency が入っている。SafeDepは637件中630件でこの経路を確認している。
{
"optionalDependencies": {
"@antv/setup": "github:antvis/G2#1916faa365f2788b6e193514872d51a242876569"
}
}
TanStack波では @tanstack/setup と github:tanstack/router#... が同じ役目を持っていた。
今回の @antv/setup と github:antvis/G2#... は、名前だけ見ると公式側の補助依存に見える。
Git依存はnpm tarballとは別にlifecycle scriptを走らせられるため、パッケージ本体とGitHub側の二重経路でpayloadを運べる。
参照されるcommit hashは支配的に 1916faa365f2788b6e193514872d51a242876569 が使われているが、SafeDepは少数バージョンで 7cb42f57561c321ecb09b4552802ae0ac55b3a7a も観測している。Aikidoの例は後者で出てくる。lockfileを調査するときは1つのhashで決め打ちせず、2つとも検索対象に入れたほうが安全だ。
引っかかりやすいのは、latest dist-tagが動いていなくても悪意あるバージョンを解決する点だ。
echarts-for-react の latest は 3.0.6 のままだったが、"echarts-for-react": "^3.0.6" のような範囲指定は、より高い 3.2.7 を解決しに行く。
その 3.2.7 が悪意あるバージョンなら、次のclean installでpayloadが走る。latest だけを確認する調査では拾えない経路だ。
攻撃チェーンはこうなる。
flowchart TD
A["侵害されたnpm公開権限"] --> B["@antvなどへ<br/>悪意あるバージョン公開"]
B --> C["利用側のnpm install<br/>semver範囲で解決"]
C --> D["preinstall<br/>bun run index.js"]
C --> E["optional dependency<br/>github:antvis/G2#..."]
D --> F["シークレット収集"]
E --> F
F --> G["C2またはGitHub repoへ流出"]
F --> H["npm tokenで<br/>次のパッケージを再公開"]
F --> I[".claude / .vscodeへ<br/>永続化"]
公開直後の悪意あるバージョンをCIが取りに行く構造は、pnpm 11やYarn 4.10のrelease-age gate記事 で書いた話とそのままつながる。
盗まれる対象もほぼ同じ顔ぶれ
Aikidoは、payloadがGitHub token、npm token、GitHub Actions OIDC token、AWS認証情報、Kubernetes service account、Vault token、SSH秘密鍵、Docker認証情報、DB接続文字列、環境変数、ローカルファイル上のシークレットを探すと書いている。
The Hacker News側では、Google Cloud、Azure、Stripe、Docker socket経由のcontainer escape試行にも触れている。
Mini Shai-Huludがワームとして広がるのは、npm tokenを取ったあとにregistry APIでpublish可能なパッケージを列挙し、tarballを落とし、payloadを混ぜ、versionを上げて再公開するからだ。
ここはTanStack波と同じで、今回の @antv 波は侵害された公開権限が大きいnamespaceに当たったぶん、可視化系の広い依存ツリーへ広がった。
流出経路では、Aikidoが t.m-kosche[.]com/api/public/otel/v1/traces へのOpenTelemetry風HTTPS送信を挙げている。
The Hacker Newsは filev2.getsession[.]org/file/ 経由のSession P2Pネットワークにも触れている。
GitHub tokenが使える場合は、被害者アカウント配下に公開リポジトリを作り、盗んだデータをJSONとしてcommitするfallbackも残っている。リポジトリ名は {単語1}-{単語2}-{番号} 形式(例: harkonnen-melange-742)、説明欄に niagA oG eW ereH :duluH-iahS(Shai-Hulud: Here We Go Again の逆順)が入る。GitHub側でこの文字列をgrepすると、Aikidoの集計では2,700件超の不審リポジトリが見つかる。
違いは開発端末への永続化が見えたこと
この波では、依存を戻したあとも端末側に起動経路が残る。
端末側IoCを最も詳しく整理しているのはSafeDepで、Claude CodeとVS Codeを次に開いたタイミングで再実行する設定が並んでいる。Aikidoは .claude/settings.json と .vscode/tasks.json に短く触れる程度で、The Hacker News側では端末永続化の話は出てこない。
| 場所 | 何が置かれる |
|---|---|
.claude/settings.json | SessionStart hookに setup.mjs 実行を追加 |
.claude/setup.mjs または .vscode/setup.mjs | payload本体(SHA256 a68dd1e6a6e35ec3771e1f94fe796f55dfe65a2b94560516ff4ac189390dfa1c) |
.vscode/tasks.json | runOn: "folderOpen" で node .claude/setup.mjs を起動 |
.github/workflows/codeql.yml | Run Copilot という名前のworkflow injection。リポジトリ側にも残る経路 |
~/.config/systemd/user/kitty-monitor.service | gh-token-monitor を常駐させるuser service |
~/.local/bin/gh-token-monitor.sh | tokenローテーション監視デーモン本体 |
~/Library/LaunchAgents/com.user.kitty-monitor.plist | macOS側の同等LaunchAgent |
~/.local/share/kitty/cat.py | kittyターミナル経由の入口 |
/var/tmp/.gh_update_state | デーモンの状態ファイル |
| GitHubアカウント | niagA oG eW ereH :duluH-iahS を説明欄に持つ公開repo |
Claude CodeやVS Codeは、開発者が次にそのプロジェクトを開いたタイミングで自動的にscriptを動かす。
.github/workflows/codeql.yml の Run Copilot は、リポジトリをcloneして次のCIを走らせた相手側でも動く。
どちらも node_modules を消す・lockfileを戻す・悪意あるバージョンをunpublishする、という手順の外側に残るので、依存を戻しただけの調査では拾えない。
node-ipcのシークレット窃取バックドア はrequire時実行、Mini Shai-Huludはinstall時実行が中心だった。
今回の波では、エディタ・AIツール起動時実行と、被害者リポジトリ経由のCI実行という発火点が増えた。
依存戻しの前後でやること
該当バージョンを npm install / pnpm install / yarn install した端末・CI runnerでは、依存戻しの前後で次を順に見る。
| # | やること | 詳細 |
|---|---|---|
| 1 | ネットワーク隔離 | 端末を一度ネットから切る。~/.local/bin/gh-token-monitor.sh などの監視デーモンが先に動いているとtoken失効を検知して破壊動作(前波では rm -rf $HOME 相当が観測されている)に入る可能性がある |
| 2 | 端末側永続化の排除 | 上の表に挙げた場所を確認し、.claude/、.vscode/、~/.config/systemd/user/、~/Library/LaunchAgents/、/var/tmp/.gh_update_state の追加ぶんを消す |
| 3 | lockfileとキャッシュ | lockfileを戻すだけでなく、package manager cache、社内npmプロキシ、Docker image layerを個別に確認する |
| 4 | リポジトリ側の確認 | 自前リポジトリの .github/workflows/ に codeql.yml の Run Copilot jobが追加されていないかチェック。あればCI履歴も追う |
| 5 | 認証情報のローテーション | npm、GitHub、AWS、GCP、Kubernetes、Vault、SSH、Docker、DB接続情報を順にrotate |
| 6 | GitHubアカウント側 | 被害者アカウント配下に niagA oG eW ereH :duluH-iahS の説明を持つ不審な公開リポジトリができていないか確認 |
「パッケージを消したか」だけで閉じると、Claude CodeとVS Codeを次に開いたタイミングで同じpayloadが端末側から走る。