ポイズン・パイプライン・エグゼキューション(PPE)とは?
OWASPのCI/CDセキュリティリスクであるポイズンパイプライン実行(PPE)は、CIパイプラインに悪意のあるコマンドを実行させる目的で、ソースコード管理(SCM)システムへのアクセス権限を悪用する攻撃ベクトルです。PPE攻撃者はビルド環境にはアクセスできませんが、SCMにはアクセスできるため、ビルドパイプラインの設定に悪意のあるコードを注入し、ビルドプロセスを操作することができます。
CICD-SEC-4:毒パイプラインの実行について
OWASP Top 10 CI/CD Security Risks の CICD-SEC-4 にリストされている Poisoned pipeline execution(PPE)は、継続的インテグレーションと継続的デプロイメント(CI/CD)システムを標的にした高度な攻撃戦略です。
お客様には様々なオプションがあります:
PPE戦略では、攻撃者は CI/CDパイプラインのCI部分内で悪意のあるコードを実行し、CI/CDシステムに直接アクセスする必要性を回避します。この方法では、ソースコード管理(SCM)リポジトリに対するパーミッションを操作します。CI設定ファイルやCIパイプラインのジョブが依存する他のファイルを変更することで、攻撃者は悪意のあるコマンドを注入し、CIパイプラインを効果的に汚染し、不正なコード実行を可能にします。
PPE 攻撃に成功すると、パイプラインの ID のコンテキスト内で実行される幅広い操作が可能になります。悪意のある操作には、CIジョブが利用可能なシークレットへのアクセス、ジョブノードが権限を持つ外部アセットへのアクセス権の獲得、一見正当なコードや成果物のパイプラインへの配送、ジョブノードのネットワークや環境内の追加のホストやアセットへのアクセスなどが含まれます。
PPE攻撃は、その重大な影響、低い検知可能性、複数の悪用テクニックの存在を考慮すると、広範な脅威となります。セキュリティチーム、エンジニア、レッドチーマーにとって、PPEとその対策を理解することは、 CI/CDセキュリティにとって非常に重要です。
パイプライン実行の定義
継続的インテグレーション(CI)の文脈では、パイプラインの実行フローは、パイプラインがビルドするリポジトリにホストされているCI設定ファイルによって定義される一連の操作を指します。このファイルには、実行されるジョブの順序の概要や、ビルド環境の設定、フローに影響する条件の詳細が記述されています。トリガーされると、パイプラインジョブは選択されたソース(例えば、コミット/ブランチ)からコードをプルし、そのコードに対してCI設定ファイルで指定されたコマンドを実行します。
パイプライン内のコマンドは、CI設定ファイルによって直接呼び出されるか、CI設定ファイルから参照される別のファイルに存在するスクリプト、コードテスト、リンターによって間接的に呼び出されます。CI設定ファイルは通常、Jenkinsfile (Jenkins)、.gitlab-ci.yml (GitLab)、.circleci/config.yml (CircleCI)、そして.github/workflowsにあるGitHub Actions YAMLファイルのように、一貫した名前と形式を持っています。
攻撃者は、パイプラインによって実行されるコマンドを直接または間接的に操作する能力を悪用することができ、攻撃者はCIで悪意のあるコードを実行するために悪用することができます。
CICD-SEC-4の悪用方法
PPE攻撃が成功するためには、重大度を満たす必要があります:
- 攻撃者は SCM リポジトリに対するパーミッションを取得する必要があります。これは、ユーザー認証情報、アクセストークン、SSH 鍵、OAuth トークン、またはその他の方法によるものです。公開リポジトリへの匿名アクセスで十分な場合もあります。
- 当該リポジトリへの変更は、追加の承認やレビューなしにCIパイプラインを起動しなければなりません。これは、リモートブランチに直接プッシュしたり、リモートブランチやフォークからのプルリクエストで変更を提案したりすることです。
- 攻撃者が取得したパーミッションは、パイプラインを実行させるイベントのトリガーを許可する必要があります。
- 攻撃者が変更できるファイルは、パイプラインによって(直接または間接的に)実行されるコマンドを定義していなければなりません。
- パイプライン・ノードは、シークレット、他のノード、コンピュート・リソースなどの非公開リソースにアクセスできなければなりません。
プルリクエストや任意のリポジトリブランチへのコミットをトリガーとして、レビューされていないコードを実行するパイプラインは、PPE の影響を受けやすくなります。攻撃者がCIパイプライン内で悪意のあるコードを実行できるようになると、パイプラインのIDのコンテキスト内で悪意のある操作を行うことができます。
毒パイプラインの3つのタイプ
ポイズンパイプラインの実行は、ダイレクトPPE(D-PPE)、インダイレクトPPE(I-PPE)、パブリックPPE(3PE)の3つの異なる形態で現れます。
ダイレクトPPE
直接 PPE シナリオでは、攻撃者は、リポジトリ上の保護されていないリモートブランチに変更を直接プッシュするか、ブランチやフォークから変更を加えたプルリクエストを送信することで、アクセス可能なリポジトリの CI 設定ファイルを変更します。パイプラインの実行は、変更されたCI設定ファイルのコマンドによって定義されたプッシュリクエストまたはプルリクエストのイベントによってトリガーされ、その結果、ビルドパイプラインがトリガーされると、ビルドノードで悪意のあるコマンドが実行されます。

図1:直接ポイズンパイプライン実行攻撃フロー
図1に示すD-PPE攻撃の例は、次のような一連のステップで行われます:
- 敵対者はリポジトリ内で新しいリモートブランチを開始し、GitHub組織内に保存されているAWS認証情報を取得し、攻撃者の制御下にある外部サーバーに送信する有害な指示でパイプライン設定ファイルを変更します。
- コードプッシュは、悪意のあるパイプライン設定ファイルを含むコードをリポジトリからプルするパイプラインをアクティブにします。
- パイプラインは、攻撃者によって汚染された設定ファイルに従って動作します。悪意のある命令は、リポジトリ・シークレットとして保存されているAWS認証情報をメモリにロードするよう命令します。
- 攻撃者の指示に従い、パイプラインはAWS認証情報を攻撃者のコントロール下にあるサーバーに送信するタスクを実行します。
- 盗まれた認証情報を手にした攻撃者は、本番環境に侵入する能力を獲得します。
間接的PPE
間接的 PPE は、SCM リポジトリにアクセスできる敵対者が D-PPE の可能性を利用できない場合に発生します:
- パイプラインが、同じリポジトリ内の別の保護されたブランチからCI設定ファイルをプルするように設定されている場合。
- CI設定ファイルがソースコードとは別のリポジトリに保存され、ユーザーが直接編集するオプションがない場合。
- CIビルドが、ソースコードに格納されたファイルではなく、CIシステム自体で定義されている場合。
このようなシナリオでも、攻撃者は、パイプライン設定ファイル内から参照されるスクリプト、コードテスト、あるいは CI で使用されるリンターやセキュリティスキャナのような自動ツールなど、パイプライン設定ファイルによって参照されるファイルに悪意のあるコードを注入することによって、パイプラインを汚染することができます。例えば
- make ユーティリティは、Makefile ファイルで定義されたコマンドを実行します。
- ソースコードそのものと同じリポジトリに格納されている、パイプライン設定ファイル内から参照されるスクリプト(例: python myscript.py - 攻撃者はmyscript.pyを操作します)。
- コードテスト:ビルドプロセスの中でアプリケーションコード上で動作するテストフレームワークは、ソースコードと同じリポジトリに保存された専用ファイルに依存しています。テストを担当するコードを操作できる攻撃者は、ビルドの内部で悪意のあるコマンドを実行することができます。
- 自動ツール:CIで使用されるリンターとセキュリティスキャナーは、一般的に、リポジトリに存在する設定ファイルに依存し、設定ファイル内で定義された場所から外部コードをロードして実行します。
間接的なPPE攻撃を行う攻撃者は、直接的なPPEによってパイプラインを汚染するのではなく、設定ファイルによって参照されるファイルに悪意のあるコードを注入します。悪意のあるコードは最終的にパイプラインノード上で実行され、ファイル内で宣言されたコマンドを実行します。

図2:間接毒パイプライン実行攻撃フロー
このI-PPE攻撃の例では、一連の出来事は次のように展開します:
- 攻撃者はリポジトリにプルリクエストを作成し、悪意のあるコマンドを Makefile ファイルに追加します。
- パイプラインはリポジトリに対するPRがトリガーされるように設定されているため、Jenkinsパイプラインがトリガーされ、悪意のあるMakefileを含むリポジトリからコードを取得します。
- パイプラインは、メインブランチに保存されている設定ファイルに基づいて実行されます。ビルドステージに入り、元のJenkinsfileで定義されているように、AWSの認証情報を環境変数にロードします。そして、make buildコマンドを実行し、Makefileに追加された悪意のあるコマンドを実行します。
- Makefileで定義された悪意のあるビルド関数が実行され、攻撃者がコントロールするサーバーにAWSの認証情報が送信されます。
- 攻撃者は盗んだ認証情報を使ってAWSの本番環境にアクセスすることができます。
公共PPE
パブリックPPEは、インターネット上で匿名の攻撃者によって実行されるPPE攻撃の一種です。公開リポジトリでは、通常プル・リクエストを作成することで、誰でも貢献できるようになっています。パブリックリポジトリのCIパイプラインが、匿名ユーザーによって提案されたレビューされていないコードを実行すると、パブリックPPE攻撃を受けやすくなります。脆弱な公開リポジトリのパイプラインがプライベートなものと同じCIインスタンス上で動作している場合、公開PPEはプライベートなプロジェクトの秘密などの内部資産も暴露する可能性があります。
CI/CDにおけるセキュアなパイプライン実行の重要性
PPE 攻撃の成功により、CI 内でレビューされていない悪意のあるコードを実行することで、攻撃者はビルドジョブと同レベルのアクセスと能力を得ることができます:
- 環境変数として注入されたシークレットやCIに保存された追加のシークレットなど、CIジョブが利用可能なシークレットへのアクセス。コードのビルドと成果物のデプロイを担当するCI/CDシステムには、通常、クラウドプロバイダ、成果物レジストリ、SCM自体など、価値の高いクレデンシャルやトークンが多数含まれています。
- ノードのファイルシステムに保存されているファイルや、基盤となるホストからアクセス可能なクラウド環境への認証情報など、ジョブノードがアクセス権限を持つ外部資産へのアクセス。
- ビルドプロセスによってビルドされた正当なコードを装って、パイプラインのさらに下流にコードと成果物を出荷する能力。
- ジョブ・ノードのネットワーク/環境内の追加ホストやアセットにアクセスする能力。
しかし組織は、コンパイル、テスト、デプロイされたすべてのコードが改ざんされていない正当なものであることを保証するセキュアなパイプライン実行によって、ソフトウェア製品とインフラストラクチャを保護することができます。
毒パイプラインの実行に伴うリスク
PPEの影響は重大で、不正なデータアクセス、ソフトウェアの完全性の侵害、システムの中断、データ侵害、さらにはシステムの乗っ取りまで、多岐にわたります。このようなリスクは、事業とその顧客の双方に重大な脅威をもたらし、PPEの重要性を際立たせています。

図3:毒されたCIパイプラインの下流への影響
図 3 に示す 8 段階のサプライチェーン侵害操作では、攻撃者は CI パイプラインにアクセスし、SaaS アプリケーションのコンポーネントを汚染します。ポイズニングされたコンポーネントを介して、攻撃者はアプリケーションにバックドア機能を構築し、ポイズニングされたプラグインを下流のクライアントに送信します。下流の組織は、毒入りパッケージを正規のものと認識する可能性が高いため、クラウドやオンプレミスのインフラに組み込みます。
攻撃者は、1つの不正なCIパイプラインから、無数の組織へのバックドアアクセスを作成し、指数関数的なコラテラルダメージを達成します。 ソーラーウインズの攻撃がそうでした。
続きを読む CI/CDパイプライン攻撃の解剖図
毒パイプライン実行の防止
PPE攻撃ベクトルの防止と軽減には、SCMとCIシステムの両方にまたがる複数の測定可能な対策が必要です:
- レビューされていないコードを実行するパイプラインは、隔離されたノードで実行され、機密やセンシティブな環境にさらされることはありません。
- 外部コントリビューターのパブリックリポジトリでパイプラインをトリガーする必要性を評価します。可能であれば、フォークを起点とするパイプラインの実行を控え、パイプラインの実行に手動承認を要件とするなどのコントロールを追加することを検討してください。
- 機密性の高いパイプライン(たとえば、秘密にさらされるパイプラインなど)については、CIシステムでパイプラインをトリガーするように設定された各ブランチが、SCMで相関ブランチ保護ルールを持つことを確認してください。
- パイプラインで悪意のあるコードを実行するためのCI設定ファイルの操作を防ぐために、パイプラインの実行前に各CI設定ファイルをレビューする必要があります。あるいは、CI設定ファイルは、パイプラインでビルドされるコードを含むブランチとは別のリモートブランチで管理することもできます。リモートブランチは保護されているように設定する必要があります。
- SCM リポジトリに付与された権限のうち、不要な権限を持つユーザーを削除します。
- 各パイプラインは、その目的を果たすために必要なクレデンシャルのみにアクセスできるべきです。クレデンシャルには最低限必要な権限が必要です。