現代のソフトウェア開発は、果てしなく続く依存関係の巨塔の上に成り立っている。開発者はnpmやPyPIといった巨大なパッケージレジストリを無意識に信頼し、毎日何百万回もインストールコマンドを叩き続けているのが現状だ。この自動化されたCI/CDパイプラインと開発者のローカル環境は、クラウドインフラを操作するAPIキーや、ソースコードリポジトリへのアクセス権限といった「神の鍵」が眠る宝物庫に他ならない。

これまで、サプライチェーン攻撃の多くはタイポスクワッティング(似た名前の偽パッケージ)や、休眠中のメンテナアカウントの乗っ取りといった、外側からの偽装に依存していた。オープンソースコミュニティはこれに対抗すべく、MFA(多要素認証)の義務化や、SLSA(Supply-chain Levels for Software Artifacts)に基づく「パッケージの出所を暗号論的に証明する仕組み」を導入して防壁を築いてきた。

だが、もし正規のメンテナが、何一つ不正な操作をしていないにもかかわらず、正規のCI/CDパイプラインを通じて「本物であるという暗号証明」付きのマルウェアが配信され始めたら、我々はどうやって身を守ればよいのか。2026年5月11日、TeamPCPと名乗る脅威アクターが放った自己増殖型ワーム「Mini Shai-Hulud」の第4波は、この悪夢を現実のものとした。TanStackMistral AI、UiPathなど、数千万回の週間ダウンロードを誇る巨大エコシステムを瞬く間に汚染したこの攻撃は、我々が信じて疑わなかった「署名と出所証明」の限界を容赦なく暴き出している。

AD

微細化する攻撃の波。進化を続ける「Shai-Hulud」の系譜

今回のインシデントは突発的なものではなく、過去1年間にわたりnpmおよびPyPIエコシステムを執拗に狙い続けてきた一連のキャンペーンの延長線上にある。セキュリティ企業StepSecurityやSnykの追跡によれば、TeamPCP(別名:DeadCatx3、PCPcat)は波を重ねるごとに戦術を高度化させてきた。

攻撃の波 発生時期 主要な標的 / 規模 技術的ブレイクスルー
Wave 1 (Shai-Hulud) 2025年9月 500以上のnpmパッケージ 初の自己増殖型npmワーム。TruffleHogを用いたシークレットの広範な抽出。
Wave 2 (Sha1-Hulud 2.0) 2025年11月 492パッケージ (月間1.3億DL) preinstall フックによるゼロクリック実行と、ホームディレクトリ破壊のフォールバック。
Wave 3 (Mini Shai-Hulud) 2026年4月 SAP / Intercom エコシステム AIコーディングエージェント(Claude Code等)への寄生。暗号化されたP2Pネットワークでのデータ持ち出し。
Wave 4 (今回のインシデント) 2026年5月 TanStack, Mistral AI等 170以上 SLSA Build Level 3の偽装。GitHub ActionsOIDCトークン窃取による正規パイプラインの乗っ取り。

第4波の最大の特徴は、感染規模そのものではない(規模面では第2波の方が大きかった)。最大の脅威は、被害者であるTanStackの正規リポジトリ(TanStack/router)が持つ強力な権限をハックし、「正規の工場で製造・梱包された」という改ざん不可能なシール(SLSAアテステーション)を貼った状態で悪意あるパッケージを出荷した点にある。

「Pwn Request」から始まる城門突破とキャッシュの汚染

TanStackのインシデント・ポストモルテムによれば、攻撃は3つの脆弱性と仕様の盲点を巧妙に連鎖させることで成立した。いかにして強固なCI/CDの壁は破られたのか。第一の突破口は、GitHub Actionsにおける pull_request_target トリガーの悪用だ。攻撃者は偽のGitHubアカウントから、一見無害なプルリクエスト(PR)を送信した。このPRは、フォークされたリポジトリ側の悪意あるコードをチェックアウトし、メインリポジトリの特権コンテキスト内でベンチマークジョブを実行させる構造になっていた。この手法はセキュリティ界隈で「Pwn Request」と呼ばれる。城の跳ね橋を不用意に下ろし、見知らぬ使者を王の玉座の間に招き入れてしまうような運用ミスである。

第二のステップは「キャッシュポイズニング」だ。PRのジョブ内で実行された悪意あるコードは、直ちにデータを盗み出すことはなかった。代わりに、後続の正規リリースビルドが使用するはずの「pnpmパッケージストア」のキャッシュを汚染した。料理人が次に使うはずの鍋の底に、あらかじめ遅効性の毒を塗りつけておく手口だ。この汚染された1.1GBのキャッシュは、8時間後に正規のメンテナがメインブランチにプッシュを行い、リリースのワークフロー(release.yml)が起動するまで静かに潜伏した。

tanstack-fig1-main.webp
悪意あるプルリクエストから始まり、GitHub Actionsのキャッシュを汚染、最終的に正規のOIDCトークンを奪取してマルウェア入りのパッケージをnpmへ公開するまでの攻撃フロー。

そして第三のステップが、OIDC(OpenID Connect)トークンの抽出である。リリースワークフローが汚染されたキャッシュを読み込み、攻撃者が仕込んだバイナリを実行した瞬間、プロセスはランナーのメモリ空間(/proc/<pid>/mem)を走査した。目的は、GitHub Actionsがnpmに対して「私はTanStackの正規リリースプロセスである」と証明するために一時的に発行するOIDCトークンの奪取だ。攻撃者はこのトークンを握りしめ、ワークフローが完了する前にnpmレジストリへ直接POSTリクエストを送信。計84の悪意あるバージョン(1.169.5や1.169.8など)が、正規の署名と出所証明を伴って公開された。セキュリティスキャナーが「出所が正しいか」をチェックしても、暗号論的には完全に「クリーン」と判定されてしまうという致命的な状況が生まれたのである。

AD

3層の暗号鎧と、AIエージェントへの寄生

被害者のローカルマシンにダウンロードされたパッケージには、本来存在しないはずの2.3MBのファイル router_init.js が隠されている。そして package.json には、GitHub上の孤立したコミットを指すオプショナル依存関係が追加されていた。開発者が npm install を実行すると、Bunランタイムを介して背後でこのペイロードが起動する。Upwind Securityの解析によれば、このコードは解析を逃れるために極めて執拗な3層の難読化が施されている。単純な文字列の配列置換(第1層)、PBKDF2-SHA256を用いた意図的に遅延処理を伴うFisher-Yates置換暗号(第2層)、そしてBunの解凍機能を要求するAES-256-GCM暗号(第3層)だ。

さらに不気味なのは、一度実行されたが最後、システムに深く根を下ろす永続化メカニズムだ。マルウェアは自身を開発ツールの中枢へとコピーする。例えばAnthropicの「Claude Code」が使用する .claude/settings.json を書き換え、開発者がAIコーディングエージェントに指示を出すたびにフックしてマルウェアを再実行させる。VS Codeのワークスペースタスク(.vscode/tasks.json)も同様にハックされる。つまり、感染に気づいて慌てて npm uninstall を実行したところで、エディタを開くたびに環境は再汚染され続けるのである。

貪欲な収穫と、分散型P2Pネットワークによるステルス搬出

バックグラウンドでデーモン化されたペイロードは、クラウドネイティブ環境のあらゆる認証情報を根こそぎ漁り始める。AWSのメタデータ(IMDSv2の正規プロセスすら突破する)、Kubernetesのサービスアカウントトークン、HashiCorp Vaultの内部エンドポイント、そしてもちろん ~/.npmrc やSSH秘密鍵。さらにはClaude Codeのセッション履歴(過去に入力したパスワードや社内コードが含まれる)までもが標的となる。

盗み出されたデータは、従来のような単一のC2(コマンド&コントロール)サーバーには送られない。Session/Oxenと呼ばれる分散型のP2Pメッセンジャーネットワーク(*.getsession.org)を経由して搬出される。これは企業環境のトラフィック監視において、エンドツーエンド暗号化された通常のチャットアプリの通信と見分けがつかない。また、フォールバックとしてGitHubのGraphQL APIを利用し、Anthropicのボットを装ったデッドドロップ・コミット(Duneの世界観にちなんだブランチ名を使用)を作成してデータを持ち出す。企業のファイアウォールがGitHubへの通信を遮断することは実質的に不可能であり、この経路は極めて凶悪だ。

AD

AIインフラを狙う地政学的ワイプ。Mistral AIパッケージの恐怖

TeamPCPの野心はJavaScriptエコシステムに留まらない。Microsoft Threat Intelligenceの調査により、Pythonエコシステム(PyPI)におけるAI開発の要、「Mistral AI」の公式パッケージ(v2.4.6)も同日に侵害されていたことが判明した。このPythonペイロードの振る舞いは、npm版とは異なる次元の悪意を孕んでいる。パッケージがインポートされた瞬間、背後でリモートIPから /tmp/transformers.pyz というファイルをダウンロードして実行する。ファイル名にHugging Faceの著名な機械学習ライブラリ「Transformers」を偽装している点は、AI開発環境に溶け込もうとする明確な意図だ。

さらにMicrosoftの報告によれば、このマルウェアには奇妙な条件分岐が存在する。システムがロシア語環境である場合は実行を停止して身を潜める。一方で、マシンのロケーションがイスラエルまたはイランであると推測される場合、1/6の確率で rm -rf / を実行し、システム全体を修復不能な状態にまで破壊するのだ。この地政学的なターゲティングと破壊ロジックは、TeamPCPが過去に展開したKubernetesプラットフォーム向けワイパー「CanisterWorm」の手口と完全に符合する。単なる金銭目的のクレデンシャル窃取を超え、特定の国家や地域のAI開発インフラそのものを物理的に破壊しようとする意図が見え隠れする。

トリアージの鉄則:トークンを失効させる「前」に爆弾を解除せよ

もしあなたのチームが5月11日以降に、影響を受けたバージョンのTanStack、Mistral AI、あるいはUiPathのパッケージをインストールしていた場合、環境は完全に侵害されたと見なすべきだ。しかし、パニックに陥ってクラウドのコンソールから無闇にトークンを無効化してはならない。セキュリティ研究者Nicholas Carliniが警告した通り、このマルウェアはローカルマシン上に「デッドマンスイッチ」を仕掛けている。Linuxでは systemd のユーザーサービスとして、macOSでは LaunchAgent として常駐し、盗み出したGitHubトークンの有効性を60秒ごとに確認し続ける。もし開発者が先にトークンを無効化し、APIが「401 Unauthorized」を返した場合、この監視スクリプトは容赦なく rm -rf ~/ をトリガーし、開発者のホームディレクトリを塵に帰す。

トリアージは、システム破壊を防ぐための厳格な手順を踏む必要がある。まず初めに、デッドマンスイッチの息の根を止めるため、システムから監視サービスを完全に停止・削除する。次に、.claude/.vscode/ ディレクトリ等に潜む不審なセットアップスクリプトを消去し、エディタへの寄生フックを取り除く。これら物理的な爆弾を解除した後で初めて、npmトークンやGitHub PAT、AWSキーなどのクレデンシャルを一斉に無効化し再発行するステップに進む。並行して、DNSレベルでのネットワーク制御(*.getsession.org および api.masscan.cloud への名前解決ブロック)も必須となる。

エコシステム防衛のパラダイムシフト

今回の「Mini Shai-Hulud」の猛威は、我々のサプライチェーンセキュリティに対する根底からの見直しを迫っている。SLSAによる出所証明は「どこでビルドされたか」を保証するが、「そのビルド環境が乗っ取られていないこと」までは保証しない。今後、開発チームはOIDCの信頼設定を根本から引き締める必要がある。リポジトリ全体に漠然と公開権限を与えるのではなく、特定の保護されたブランチと、特定のワークフローファイルにのみ権限を絞り込まなければならない。

OIDCの信頼設定 設定の記述例 脆弱性の有無と理由
リポジトリ単位の包括的許可 (脆弱) Repository: tanstack/router フォークからのPR等、意図しないワークフローが介入してもnpmへの公開権限を奪取されてしまう。
ブランチ・ワークフロー単位の制限 (安全) Workflow: .github/workflows/release.yml
Branch: refs/heads/main 指定されたメインブランチ上の正規リリースプロセス以外では、OIDCトークンが一切発行されない。

さらに、pull_request_target を用いたワークフローでフォーク側のコードをチェックアウトする危険な運用を直ちに廃止し、pnpmやBunの設定で min-release-age(公開から一定時間経過していないパッケージのインストールを拒否する設定)を導入する自衛策が急務となる。誰もが利用するインフラが武器に変わる時代。パッケージの署名を盲信するフェーズは終わった。インストール時の振る舞い検知と、CI/CD環境そのものの厳格なゼロトラスト・アーキテクチャの構築が、生き残るための最低条件となっている。