シャイ・ハルド 第2部:Worm が独自のセキュリティ証明書Worm とき

May 13, 2026
5/13/2026
Lucie Cardiet
サイバー脅威リサーチマネージャー
シャイ・ハルド 第2部:Worm が独自のセキュリティ証明書Worm とき

今朝、TeamPCPworm Shai-Huludworm 完全なソースコードを公開した。MITライセンス。リポジトリは2つ。公開から数時間のうちに44件のフォークが発生し、そのうちの1つは、ほとんどのセキュリティチームがニュースの見出しを読む前に、すでにFreeBSDへの対応を追加していた。

雰囲気は伝わる? はい。効果は? 結果が物語っています。必要に応じてキーとC2を変更してください。愛を込めて ― TeamPCP

昨年、Shai-Huludについて記事を書きました。その記事では、worm 基本的な動作メカニズムについて解説しました。具体的には、パッケージのインストールプロセスにworm 、検出を回避するためにランタイムを切り替える方法、認証情報を収集する方法、公開されたGitHubリポジトリを通じて情報を流出させる方法、そして被害者がエコシステムに対して抱く既存の信頼を利用することで拡散する方法などです。

その仕組みは今も変わりません。しかし、2026年5月にTanStackやその他170以上のパッケージを標的とした攻撃では、当初の投稿では触れられていなかった新たな手法が用いられました。このworm 、自身の悪意あるパッケージを認証済みのように見せかける方法をworm 。

のスクリーンショット GitHubリポジトリの TeamPCPによって公開された

TanStackキャンペーンで何が変わったのか

これまでのShai-Huludによる攻撃では、そのworm npmトークンをworm 、被害者のアカウント名で悪意のあるパッケージを公開していました。これらのパッケージは、既知の発行元から配信されていたため、一見正当なものに見えました。そこが罠だったのです。

TanStackキャンペーンでは、新たな手順が追加されました。Wiz、StepSecurity、Snykが発表した調査によると、worm itHub ActionsランナープロセスのメモリからOIDCトークンをworm 。その後、そのトークンを使用して、SigstoreのFulcio認証局から暗号署名証明書を取得しました。そして、その証明書を用いて悪意のあるパッケージに署名を行いました。

その結果、この悪意のあるパッケージには、有効なSLSAビルドレベル3の来歴証明書が付与されていた。偽造されたものではなく、Sigstoreが被害者のGitHub Actionsアカウントに対して発行した正当な証明書であった。

盗まれた認証情報は、この攻撃のために特別に登録された偽装ドメイン「git-tanstack[.]com」に流出させられ、Session Networkのエンドポイントや、Duneをテーマにした一連のGitHubリポジトリも同様に流出しました。攻撃が行われている間、TeamPCPはこのドメインに次のようなメッセージを残していました:

2026年5月の実攻撃中に、TeamPCPがC2ドメイン「git-tanstack[.]com」に残したメッセージ。出典:Wiz。
(YouTubeのリンク先は、Martin Solveigの楽曲『Hello』のミュージックビデオです。ペイロードではありません。)

OIDCトークンとは何か、そしてなぜそれらがランナーメモリに存在するのか

OIDCはOpenID Connectの略称です。GitHub Actionsの文脈において、これは特定の認証情報管理上の課題 を解決します。つまり、CI/CDパイプラインが、リポジトリに長期保存されるシークレットを保存することなく外部サービス(npmレジストリ、クラウドプロバイダー、Sigstoreなど)への認証を行う必要があるという課題です。

解決策は、有効期間が短いトークンを使用することです。ジョブが実行されると、GitHubのOIDCプロバイダーは、その特定のジョブ(このワークフロー、このリポジトリ、このコミット、このアクター)を識別するトークンを発行します。このトークンは、環境変数およびローカルエンドポイントを通じてランナーから利用可能です。トークンは発行後数分以内に失効します

セキュリティ上の前提として、トークンは一時的なものであり、スコープが限定されていることが挙げられます。開発者が保存したシークレットを悪用した攻撃者であっても、以前のジョブで使用されたトークンはすでに有効期限が切れているため、それを再利用することはできません。この前提は、通常の状況下では妥当なものです。

このworm 通常の状態では動作worm トークンが有効になった瞬間に、Actionsジョブ内部でコードを実行します。

抽出の仕組み(実際の運用例)

worm は ACTIONS_ID_TOKEN_REQUEST_TOKEN ランナープロセスから環境変数を取得し、それを使用して GitHubのOIDCエンドポイントからOIDCトークンをリクエストする. その後、 そのトークンをSigstoreのFulcio CAに提示するこれにより、GitHub ActionsのジョブIDに紐付けられた有効期間の短いX.509証明書が発行されます。その証明書とRekorの透明性ログへのエントリを用いて、 このworm 、公開しようとしているパッケージに対して、有効なCosign署名とSLSAプロバンス証明書をworm.

各ステップは、正規のサービスに対する正当なAPI呼び出しです。ランナーには、これらすべてを実行する権限があります。そこが重要な点です。悪意のあるコードは、リポジトリの信頼設定を通じてそれらの権限を取得したジョブ内で実行されており、設計通りにその権限を利用しています。

出所確認が失敗する理由

SLSAの来歴検証は、ある特定の疑問に答えることを目的としています。すなわち、「このアーティファクトは、想定されたビルドシステムによって、想定されたソースから、不正な干渉を受けることなく構築されたのか」という疑問です。ビルドレベル3では、ジョブが自身の来歴を改ざんできないよう、堅牢なビルド環境が特に求められます。

Shai-Hulud OIDC手法は、設計上の仮定を回避するものであり、技術的な制御を回避するものではない

  • ビルドシステムに問題はありません
  • OIDCエンドポイントは侵害されていません。
  • SigstoreのFulcio CAは侵害されていません

この検証では、ジョブ内で実行されたコードが、メンテナンス担当者が実行するつもりだったコードではなかったという事実を把握することはできません。このworm 、パイプラインの初期段階でインストールされた依存関係を通じてworm 。

Sigstoreの観点から見れば、正当なGitHub Actionsランナーが、正当なリポジトリのIDの下で動作し、 正当なアーティファクトに署名したことになりますこの証明は、これらの事実については正確ですただし、ペイロードがどのようにしてそこに到達したかについては言及されていません。

この証明書は、署名者の身元を確認するものです。署名者の意図や、同じプロセス内で他に何が実行されていたかについては確認しません。

問題は1つではなく、2つある

Shai-Huludに関する当初の投稿では 、この問題を「一見して異常が見当たらない」という性質のものとして捉えていました 。つまり、worm個々の動作――パッケージのインストール、スクリプトの実行、npmへの公開――はすべて日常的な操作であり、malware 生成することもなければ、ポリシー違反を引き起こすこともありません。各ステップは、すべて通常の開発作業のように見えるのです。

OIDCの手法には、もう1つ関連する問題があります。それは、その動き自体が可視化されないという点です。トークンの抽出とSigstoreへの署名リクエストは、CI/CDトラストファブリックのIDレイヤーを通る横方向の移動に他なりません。worm GitHubからフェデレーテッド認証情報をworm 、それをSigstoreに提示することで、被害者のプロヴェナンス・チェーンの下でnpmへの公開を許可する証明書を受け取ります。この動きは、GitHubのOIDCプロバイダー、SigstoreのCA、そしてnpmレジストリという3つの異なるシステムを横断します。各システムは、一見問題のない認証イベントとしてこれをログに記録します。

つまり、監査ログが3件あり、認証も3回成功しています。存在しないログエントリこそが、それらの呼び出しを行ったコードが本来そこにあってはならないことを示しているのです。

Mind Your Attack Gaps』で私が用いている枠組みにおいて、これらは3つの主要な検知ギャップのうちの2つ、「異常が見られない」(ギャップ1)と「動きが確認できない」(ギャップ3)に該当します。ほとんどのサプライチェーン攻撃は、このうち1つを引き起こします。しかし、この手法は両方を同時に引き起こすため、170種類のパッケージに対する自動スキャンを経ても、どのベンダーもこれを検知できなかったのです。

オープンソース化による変更点

今日に至るまで、OIDC抽出技術は単一のグループに帰属していました。この技術が関与したすべてのインシデントは、TeamPCPに遡ることができました。Wiz、Ox Security、ReversingLabsによるフォレンジック分析では、C2ドメイン、ペイロードのファイル名、Session NetworkやDuneをテーマにしたリポジトリへの情報流出パターンといった、彼ら特有の指標を特定することができました。

オープンソース化により、その封じ込めモデルは崩壊します。リポジトリをフォークした者は誰でも、OIDCの抽出機能を利用できるようになります。具体的な指標はバリエーションごとに異なりますが、手法自体は変わりません。

リポジトリが公開されてから数時間以内に追加されたFreeBSDのフォークは、そのスピードを如実に物語っている。worm 、オリジナル版ではテストされたことのないプラットフォームでも動作する。PyPIは、2026年5月のキャンペーンにおける標的エコシステムとして確認されている。RubyGemsとMavenが、次なる有力な候補である。5月11日の5時間という短期間に、170のパッケージにわたり公開された401の悪意あるパッケージのバージョンは、基準となる数値を示している。このツールキットを使用する派生グループの行動も、これより遅くなることはないだろう。

XのTeamPCPアカウントへの投稿「今年はサプライチェーンの年だ。君たちはこれから長い間、大忙しになるだろう」 - 2026年3月31日

検知の仕組み

アーティファクトのスキャンではこれを検出できません。アテステーションは有効です。署名も有効です。パッケージは機能的に問題ありません。インストール前にSLSAの来歴を確認する下流の利用者は、チェックに合格した結果を確認することになります。

これらの兆候は動作上のものですが、これらは悪意のあるパッケージが公開される前に現れます。OIDCトークンを要求し、SigstoreのFulcioエンドポイントを呼び出すCIランナー自体は、それ自体としては珍しいことではありません。しかし、そのような動作を行うランナーが、同じジョブの実行中に見慣れないホストへのアウトバウンド接続も行っている場合、その一連の動作は調査する価値があります。同じランナーセッション内で異常なネットワーク活動に続いて行われるパッケージの公開こそが、捕捉すべき一連の動作です。

元の投稿では次のような行動上の兆候が挙げられていました:GitHubトークンによる予期せぬ規模のリポジトリ作成、宣言されたジョブの範囲を超えてクラウドシークレットを読み取るCIランナー、これまで使用したことのないサービスを呼び出すクラウドキーなどです。新たに追加されたのは、OIDCリクエスト、Sigstore API呼び出し、およびnpmパブリッシュであり、これらはすべて同じジョブ内で実行され、見慣れないアウトバウンド接続も発生させていました。

それぞれの行動は正当である。しかし、その組み合わせは正当ではない。

なぜ環境をまたぐコンテキストがここで重要なのか

Vectra AI は、ID管理システム、ネットワーク、クラウド環境全体にわたる行動パターンを監視します。サプライチェーンのインシデントにおいて、関連するシグナルが単一のログに記録されることはほとんどありません。重要なのは相関関係です。このランナーは、ログを出力する前に何を行っていたのか?このジョブのネットワークトラフィックに、過去50回の実行時には存在しなかった外部ホストがどのように現れたのか?このクラウドキーは、これまで呼び出したことのないどのような呼び出しを行ったのか?

Shai-Huludが提起する検知上の課題は、シグネチャの問題ではありません。それはコンテキストの問題です。そのコンテキストは、3つの監査ログと1つのネットワークトレースにまたがって存在します。これらを相互に関連づけることで、悪意のあるパッケージが下流の受信者に到達する前に、worm行動パターンを特定することが可能になります。

--

フェデレーテッドID認証情報がCI/CDトラストファブリック内を横断的に移動し、下流のサービスで認証を行うという、より広範なパターンこそが、私が 『Mind Your Attack Gaps』電子書籍で「移動が可視化されない」ギャップ(Gap 3)として解説しているものです。第3章では、OAuthサプライチェーンの波を主なケーススタディとして、環境を横断する移動パターンを詳細に解説しています。Shai-Hulud OIDCの手法は、SaaS層ではなくビルドパイプライン内部における同様の構造的な問題です。

--

一次資料:

よくある質問 (FAQ)