2026年に報告されたCVEは、1日あたり前年比131%増加しています。

レッドチーム vs ブルーチーム

サプライチェーン攻撃:攻撃者はどう侵入し、どう止めるか

攻撃者が自社を直接狙うことはまれです。狙うのは、あらゆる企業が依存しているパッケージ、Action、ビルドツールであり、そのうえで全員に一斉にエクスプロイトを試します。攻撃者には自社の依存関係の一覧は必要ありません。必要なのは自社のほうです。

ソフトウェアサプライチェーン攻撃とは

ソフトウェアサプライチェーン攻撃は、製品を直接攻撃するのではなく、オープンソースパッケージ、CI/CDコンポーネント、ビルドシステムなど、製品を構成するものを侵害します。現代のソフトウェアの大部分は他者が書いたコードです。その多くはオープンソースパッケージから来ており、さらにその多くはチームの誰も選んでいない推移的依存関係です。広く使われているコンポーネントを1つ侵害すれば、それを基盤とするすべての組織に到達できます。

これにより、攻撃者の標的の選び方が変わります。1社の依存関係を調べるのではなく、影響範囲の大きいパッケージやツールを選び、あらゆる場所でそれを悪用して、何が応答するかを確認するのです。

ソフトウェアサプライチェーン攻撃の種類

脆弱な依存関係の悪用

人気のオープンソースパッケージの欠陥が公開されると、攻撃者は脆弱なバージョンを出荷しているすべての製品でそれを悪用します。多くの場合、それは誰も直接選んでいない推移的依存関係です。

悪意あるパッケージのリリース

攻撃者がメンテナーのアカウントを乗っ取るか、ワームが公開用のトークンを盗み、信頼されたパッケージの汚染されたバージョンをリリースします。Shai-Hulud npmワームのように、ビルドがインストールした瞬間に実行されます。

上流プロジェクトへのバックドア

コントリビューターが時間をかけてオープンソースプロジェクトの信頼を得たうえで、下流のディストリビューションや製品が取り込むリリースに悪意あるコードを紛れ込ませます。xz utilsのバックドアがその例です。

タイポスクワッティングと依存関係の混乱(Dependency Confusion)

人気パッケージに似た名前のパッケージが入力ミスを狙います。Dependency Confusionはさらに踏み込み、企業の内部パッケージと同じ名前の公開パッケージが、内部パッケージの代わりにインストールされます。

侵害されたCI/CDコンポーネント

GitHub Actionなどのビルドツールが乗っ取られ、それを使うすべてのパイプラインが、シークレットに手が届く状態で攻撃者のコードを実行します。tj-actionsやCodecovがその例です。

ビルドと成果物の改ざん

ビルドそのものが改変されるか、ビルドとデプロイの間で成果物がすり替えられるため、クリーンなソースツリーからでも侵害されたリリースが生まれます。SolarWindsがその例です。

サプライチェーン攻撃の実例

最もよく知られたサプライチェーン攻撃はSolarWindsです。ビルドで悪意あるコードが挿入され、通常のアップデートとして顧客に出荷されました。最近の攻撃は、パッケージレジストリやCIパイプラインを狙います。そこでは、侵害されたパッケージやActionが1つあれば、それを使うすべてのビルドに到達できます。新しい順に紹介します。

npmワーム · 2025年9月以降

Shai-Hulud

感染したnpmパッケージがインストールされると実行される自己増殖型のワームで、npm、GitHub、クラウドのトークンを盗み、被害者の他のパッケージの感染バージョンを公開します。感染の大半はCI内で発生しました。

ビルドを確認する方法 →

CVE-2025-30066 · 2025年3月

tj-actions/changed-files

CISAの報告によると、この人気のGitHub Actionはすべてのバージョンが3日間侵害され、シークレットがワークフローのログに露出しました。タグで参照していたワークフローは攻撃者のコードを実行しました。

CVE-2024-3094 · 2024年3月

xz utilsのバックドア

Andres Freundは、SSHログインのCPU使用率が高すぎることに気づき、xzのバージョン5.6.0と5.6.1にバックドアを発見しました。バックドアは上流プロジェクトそのものに仕込まれていました。

CVE-2021-44228 · 2021年12月

Log4Shell

Apache Log4j 2の欠陥により、ログに記録されるメッセージを制御できる攻撃者が任意のコードを実行できました。CVSSは10.0です。多くのチームにとって難しかったのは、どのアプリケーションにlog4j-coreが含まれているかを見つけることでした。たいていは依存関係の依存関係として含まれていました。

2021年1月〜4月

Codecov Bash Uploader

攻撃者は、チームがCIパイプラインで実行していたBash Uploaderスクリプトを改変し、認証情報、トークン、キーを含むCI環境をCodecovのインフラ外のサーバーに送信させました。1月31日から、顧客が4月1日に報告するまで気づかれずに実行されていました。

SUNBURST · 2020年12月

SolarWinds Orion

攻撃者はSolarWinds Orionのビルドプロセスに長期間ひそかにアクセスし、Orionのリリース2019.4から2020.2.1 HF1に悪意あるコードを挿入しました。顧客はそれを通常のアップデートとしてインストールしました。CISAはこれを受けて緊急指令を発出しました。

レッドチーム vs ブルーチーム

サプライチェーン攻撃の仕組みを段階ごとに解説

各段階を攻撃者の言葉で示し、それに応える防御策を紹介します。

ステージ 1 / 3

偵察

標的を知る必要はない。パッケージを選べば、標的は勝手に決まる。

レッドチーム

誰もが持つ依存関係に賭ける

相手のロックファイルは要らない。人気パッケージはほぼあらゆるものの推移的依存関係ツリーの奥深くにあり、ほとんどのチームは自分たちがどれを出荷しているか答えられない。公開されている手がかりで絞り込める。JavaScriptバンドルやHTTPヘッダーのバージョン、公開リポジトリ、コンテナイメージ。そして、postinstallスクリプトがダウンロードするバイナリやベースイメージの下のレイヤーなど、ロックファイルの外でビルドが取得するものは相手のスキャナーには見えていない。だから誰もパッチを当てていない。

ブルーチーム

各ビルドが取り込んだすべての依存関係を把握

CRACIはすべてのビルドに入ってくる通信を見て、ビルドが取り込むすべてのパッケージとファイルを記録します。ロックファイルベースのツールが見落とす隠れた依存関係も、推移的依存関係ツリーのあらゆる階層で記録します。SBOMは出荷したビルドから作成されるため、攻撃者が必要としなかった一覧を、誰かが探し始める前に手元に用意できます。

ビルド時SBOM →

レッドチーム

新しいCVEが出た瞬間に動く

新しいアドバイザリには、どのバージョンが脆弱かが正確に書いてある。エクスプロイトを作り、応答するものをスキャンし、スキャン結果に相手が誰かを教えてもらう。相手のチームがまだSlackのスレッドで「うちは影響を受ける?」と聞いている間に、こちらは当日から動き出せる。

ブルーチーム

「影響を受けるか」にビルドの記録から回答

CRACIは監視対象のSBOMを新しい脆弱性データと継続的に照合して再評価します。ビルド履歴から、脆弱な依存関係(直接・推移的を問わず)を含んでいたビルドがわかるため、それがどこに、どれだけの期間出荷されていたかを把握できます。

影響を受けるか? →

ステージ 2 / 3

侵入

パッチが当たる前に欠陥を突くか、欠陥を使わずにパイプラインに便乗する。

レッドチーム

公開当日に攻撃を生成する

AIは、相手のセキュリティチームがチケットをトリアージする前に、アドバイザリとパッチの差分から実際に動く攻撃を作り出す。公開はスタートの合図だ。相手のスプリント計画は来週だ。

ブルーチーム

脆弱なバージョンの出荷を止める

ポリシーゲートは、特定のCVEを含むビルドをブロックできます。そのため、依存関係ツリーのどれほど深くにあっても、判断したその瞬間から脆弱なバージョンの出荷を止められます。

CVEの修正 →

レッドチーム

タグを1つ書き換えて、千のパイプラインで実行する

ワークフローは@v4のようなタグを信頼しているが、タグは移動できる。人気のGitHub Actionを1つ侵害すれば、それを使うすべてのワークフローが、シークレットに手が届く状態でこちらのコードを実行する。

ブルーチーム

各ビルドが実行したActionを正確に把握

CRACIは、ワークフローが実行するGitHub Actionsを、実際に実行されたコミットに固定した形でビルドのSBOMに記録します。Actionが侵害されたとき、タグから推測するのではなく、どのビルドが不正なコードを実行したかを確認できます。

CI/CDセキュリティチェックリスト →

ステージ 3 / 3

持ち出し

シークレットを奪い、さらに次を狙って居座る。

レッドチーム

相手のCIから外部に通信する

悪意あるパッケージのリリースは、トークンやクラウドの認証情報が置かれている相手のビルドの中でインストールスクリプトを実行する。CIランナーはたいていインターネット全体に接続できるので、パッケージが悪質だと誰かが気づく前に、シークレットはこちらのサーバーへ送られる。

ブルーチーム

ビルドは必要な接続先にしか到達できない

エグレスポリシーをデフォルト拒否に設定すると、ビルドはパッケージソースと公開先にのみ到達でき、それ以外はすべてブロックされます。マルウェアがシークレットを攻撃者のホストに送信しようとしても、誰も見たことのない攻撃の最初の被害者になる場合でもブロックされ、ポリシー違反のアラートが届きます。

エグレスポリシー →

レッドチーム

次のジョブまでランナーに居座る

長期間稼働するセルフホストランナーは格好の獲物だ。ワークスペースやツールキャッシュに何かを仕込んで、次のジョブと、次のシークレットがやって来るのを待てばいい。

ブルーチーム

ジョブごとに分離された仮想マシン

CRACIのジョブはすべて専用の分離された仮想マシンで実行されるため、あるジョブが残したものが次のジョブを待ち構えることはありません。パッチを当てて堅牢化しなければならないランナーのフリートもありません。

マネージドとセルフホストのランナー →

公開後

アドバイザリが公開された瞬間に競争が始まる

攻撃者は、自社がその依存関係を使っていることを知る必要はありません。あらゆる場所でエクスプロイトを試し、何が応答するかを見るだけです。自社のチームは、その依存関係がどこに出荷されたかを知る必要があります。違いは、探しに行かなければならないかどうかです。そしてこの競争は毎年増えています。1日に公開されるCVEの数をご覧ください。

レッドチーム

  1. アドバイザリ公開
  2. エクスプロイト生成
  3. 脆弱なバージョンを実行しているものをスキャン
  4. 一致したすべての環境に侵入(自社を含む)

ブルーチーム(ビルドの記録なし)

  1. アドバイザリ公開
  2. 「うちは影響を受ける?」
  3. リポジトリ、ロックファイル、イメージをgrep
  4. 誰も把握していなかった推移的なコピーを発見
  5. どのリリースで出荷されたかを調査
  6. パッチ適用

ブルーチーム(CRACIあり)

  1. アドバイザリ公開
  2. 監視対象のSBOMを再評価
  3. ビルド履歴で該当ビルドと期間を確認
  4. ポリシーゲートがCVEを含む新規ビルドをブロック

ソフトウェアサプライチェーン攻撃の防ぎ方

1つの対策ですべてのサプライチェーン攻撃を防げるわけではありません。これらを重ねることで、上記のどの段階でも攻撃が難しくなります。パイプライン側の詳細は、CI/CDパイプラインセキュリティチェックリストをご覧ください。

  1. すべてのビルドが出荷するものを把握する。 推移的依存関係やロックファイルの外で取得されたものも含め、ビルドごとにSBOMを保持してください。リポジトリのスキャンは、リリースの記録ではありません。
  2. デフォルトブランチだけでなく、出荷したものを監視する。 リリース済みのビルドを新しいアドバイザリと照合し直し、いつから影響を受けていたかがわかるビルド履歴を保持してください。
  3. 依存関係とActionを固定する。 ロックファイルを使い、GitHub Actionsは完全な長さのコミットSHAで固定してください。GitHubは、これがActionを不変のリリースとして使う唯一の方法だとしています。
  4. 脆弱なバージョンをビルドで止める。 出荷してはならないと判断した脆弱性でビルドをゲートし、修正がいつの間にか元に戻ることを防ぎます。
  5. CIのエグレスをデフォルト拒否にする。 ビルドがパッケージソースと公開先にのみ到達できるようにすれば、誰も見たことのない攻撃でも、悪意あるコードがシークレットを外部に送信できなくなります。
  6. ジョブを分離し、シークレットを制限する。 各ジョブを新しい分離されたマシンで実行し、各ジョブには必要なトークンと権限だけを与えてください。
  7. デプロイ前に成果物を検証する。 ビルド時に来歴に署名し、本番環境で動いているものがビルドされたものと完全に同じであることを確認してください。
  8. インシデント後はシークレットをローテーションする。 侵害されたパッケージやActionがパイプラインで実行された場合、それが到達できたすべてのシークレットを露出したものとして扱ってください。これはtj-actionsの侵害後にCISAが出した助言です。

攻撃者に一覧は要らない。必要なのは自社だ。

攻撃者はすべてのアドバイザリを監視し、脆弱性が公開されたその日に全員にエクスプロイトを試します。攻撃者には自社の依存関係の一覧は必要ありませんでした。必要なのは自社のほうです。CRACIは、ビルドそのものから得たその一覧をチームに提供し、攻撃者が当てにしている扉、つまり無制限のエグレスと共有ランナーを閉じます。

サプライチェーン攻撃に関するよくあるご質問

ソフトウェアサプライチェーン攻撃とは何ですか?

製品そのものではなく、オープンソースパッケージ、CI/CDコンポーネント、ビルドシステムなど、製品を構成するコード、ツール、サービスを狙う攻撃です。1回の侵害が、影響を受けたコンポーネントを使うすべての組織に及びます。

ソフトウェアサプライチェーン攻撃にはどのような例がありますか?

Shai-Huludワーム(2025年以降)は、感染したnpmパッケージを通じて拡散し、CIのシークレットを盗みました。tj-actions/changed-filesの侵害(CVE-2025-30066)では、人気のGitHub Actionが乗っ取られました。xz utilsのバックドア(CVE-2024-3094)は、上流の圧縮ライブラリに仕込まれました。Log4Shell(CVE-2021-44228)は、広く使われているJavaのログ記録ライブラリの欠陥を悪用しました。CodecovのBash Uploader(2021年)はCIの認証情報を外部サーバーに送信するよう改変され、SolarWinds Orion(2020年)はビルドで挿入された悪意あるコードを含んだまま出荷されました。

最も有名なサプライチェーン攻撃は何ですか?

SolarWindsです。2020年、SolarWinds Orionのビルドプロセスにひそかにアクセスした攻撃者がリリースに悪意あるコードを挿入し、顧客はそれを通常のアップデートとしてインストールしました。この事件は、クリーンなソースツリーだけでは不十分であり、ビルドそのものが信頼でき、検証可能でなければならないことを示しました。

攻撃者は自社がどの依存関係を使っているかを知っているのですか?

通常は知りませんし、知る必要もありません。ほとんどの攻撃は企業ではなくパッケージを狙います。アドバイザリが公開されると、攻撃者は脆弱なバージョンを実行している可能性のあるあらゆるものにエクスプロイトを試し、何が応答するかを確認します。JavaScriptバンドルやオープンソースのリポジトリに含まれるバージョンなど、公開されている手がかりが狙いを定める助けになります。非対称なのは、防御側には一覧が必要だという点です。影響を受けるかどうかを知るには、ロックファイルの外で取得したものも含め、すべてのビルドが何を出荷したかを把握している必要があります。

ソフトウェアサプライチェーン攻撃はどう防げばよいですか?

1つの対策ですべてを防げるわけではありません。すべてのビルドが出荷するもののSBOMを保持して新しいアドバイザリに対して監視し、依存関係とGitHub Actionsを固定し、脆弱なバージョンをビルドでブロックし、CIジョブの接続先を制限し、ジョブを分離してシークレットを制限し、デプロイした成果物が自社でビルドしたものであることを検証してください。

npmのサプライチェーン攻撃にはどう対策すればよいですか?

ロックファイルをコミットしてCIではそこからインストールし、ビルドに不要な場合はインストールスクリプトを無効にしてください(npmの--ignore-scripts)。各ビルドが実際にインストールしたパッケージのバージョンを記録しておけば、Shai-Huludのような新たな攻撃の波が発表されたときにすばやく確認できます。CIジョブの接続先を制限して、悪意あるインストールスクリプトがトークンを外部に送信できないようにし、感染したバージョンが到達できた可能性のあるトークンはすべてローテーションしてください。

ここでいうレッドチームとブルーチームとは何ですか?

セキュリティ演習では、レッドチームが攻撃者を演じ、ブルーチームが防御します。このページも同じ構成で、サプライチェーン攻撃の各段階を攻撃者の言葉で示し、それに防御側が応えます。

CRACIは悪意あるパッケージを検出しますか?

既知のものは検出します。xzのバックドアのように公開されたCVEがある悪意あるリリースは、他の脆弱性と同様にフラグが立てられ、ポリシーゲートでそれを含むビルドをブロックできます。CRACIはパッケージの挙動を解析したり評判をスコアリングしたりしないため、まったく新しい悪意あるパッケージは、アドバイザリが出るまでフラグが立ちません。そのためにあるのがエグレスポリシーです。デフォルト拒否であれば、ビルドは必要なホストにしか到達できないため、誰も見たことのない攻撃でも、パッケージがシークレットを外部に送信することはできません。