1 ポイント 投稿者 GN⁺ 2025-04-01 | 1件のコメント | WhatsAppで共有
  • 公開された GITHUB_TOKEN が短時間だけ有効になる隙を突くと、CodeQL を使う複数のリポジトリの GitHub Actions ワークフローでコード実行につながり得るサプライチェーン攻撃経路が開かれる可能性があった
  • このトークンは github/codeql-action リポジトリの失敗したデバッグワークフローがアップロードした workflow artifact に含まれており、contents: write, actions: write, packages: write 権限を持つ GitHub App インストールトークンだった
  • 攻撃の成否は、artifact のアップロード後からジョブ終了前までにトークンをダウンロードして使う レースコンディション にかかっており、実際のログ基準では約 1.022 秒、観測上は約 2 秒以内に branch 作成、poc.txt の push、tag 作成が成功した
  • デフォルトの CodeQL 設定が内部的に github/codeql-actionv3 tag を実行し、その tag が不変ではなかったため、攻撃者が tag を悪意ある commit に移せば、デフォルトの CodeQL ワークフローを使うリポジトリまで影響を受ける可能性があった
  • GitHub は報告から約 3 時間後にデバッグ artifact アップロードを無効化する PR を出し、CVE-2025-24362 を割り当て、advisory でプラットフォームやシステム侵害の証拠はないと明らかにした

公開された artifact から始まる CodeQL サプライチェーン攻撃経路

  • 公開された secret 1 つが GitHub CodeQL に対する潜在的な サプライチェーン攻撃 につながる可能性があった
  • この secret は一度に約 1.022 秒 の間しか有効でなかったが、その間に攻撃者は GitHub Actions ワークフロー内部でコードを実行できる段階まで進めることができた
  • 影響範囲は GitHub Cloud と GitHub Enterprise の両方に及び得た
  • 想定される被害は次のとおりだった
    • CodeQL を使用する private リポジトリの ソースコード流出
    • CodeQL ワークフロー job 内の GitHub Actions secrets の窃取
    • CodeQL ワークフローが動作する内部インフラ上でのコード実行
    • CodeQL を使うリポジトリで GitHub Actions Cache を使うワークフローの secrets 窃取
  • GitHub advisory によると、GitHub はプラットフォームやシステム侵害の証拠を確認していない

secret を見つけた方法

  • GitHub Actions workflow artifact をダウンロードし、圧縮を再帰的に展開したうえで、Nosey Parker で secret をスキャンする Actions Artifacts Secret Scanner が使われた
  • この機能は Chariot に統合され、Gato の機能としてオープンソース化された
  • 1 日スキャンした後、github/codeql-action リポジトリの artifact からトークンが見つかった
    • 対象 artifact は「PR Check – Debug artifacts after failure」ワークフローがアップロードした my-debug-artifacts zip だった
    • 内部の my-db-java-partial.zip を展開すると、crash report 内で ghs_ から始まる GitHub Token が検出された
    • 手動確認の結果、GitHub Runner の環境変数を含むファイル内に保存されていた GitHub App インストールトークンだった

GitHub Actions、artifact、CodeQL の接続構造

  • GitHub Actions は YAML workflow に定義された処理を runner 上で実行する CI/CD プラットフォーム である
  • すべての workflow run は自動生成される GitHub App インストールトークンである GITHUB_TOKEN を作成する
    • runner はこのトークンで GitHub に認証し、workflow が要求する処理を実行する
    • 権限は workflow ファイル、リポジトリ、組織レベルで設定できる
  • GitHub Actions workflow artifact は、workflow が後で使うために GitHub Actions に保存するファイルである
    • デフォルトでは、リポジトリの読み取り権限を持つ人がアクセスできる
    • 最大 90 日間保存される
  • CodeQL は GitHub のコード解析エンジンであり、GitHub リポジトリで静的解析を行って脆弱性を見つけるために使われる
  • CodeQL のようなセキュリティツールは機密性の高いシステムやデータにアクセスする必要がある場合があり、侵害されると バックドア になり得る

トークン権限とレースコンディション

  • ワークフローログの「Setup Job」段階で、当該 GITHUB_TOKEN がフル書き込み権限を持っていることが確認された
  • 特に重要な権限は次のとおりだった
    • contents: write: branch 作成、tag 作成、release artifact アップロードが可能
    • actions: write: Actions ジョブと workflow_dispatch event のトリガーが可能
    • packages: write: package のアップロードが可能
  • トークンは当該 workflow job の実行中のみ有効だったため、攻撃には 3 つの条件が必要だった
    • トークンに write 権限があること
    • job 完了前に artifact を取得できる upload artifact API v4 を使っていること
    • artifact のアップロードと job 完了の間に、トークンのダウンロード、展開、使用に十分な時間があること
  • CodeQL は actions/upload-artifact action を直接使わず、ソースコード内で upload artifact client を手動利用しており、コードコメント上では version 4 を使っていた
  • 生の GitHub ログ基準では時間間隔は非常に短かった
    • 「Finalizing artifact upload」: 17:22:09.888
    • 「Cleaning up orphan processes」: 17:22:10.911
    • 計算上は約 1.022 秒 で、観測上は cleanup 後も約 1 秒トークンが有効だったため、約 2 秒とみなされた

PoC: artifact_racer.py の実行

  • 検証用 Python スクリプト artifact_racer.py が作成された
  • 動作の流れは次のとおりだった
    • github/codeql-action リポジトリで「PR Check – Debug artifacts after failure」ワークフローが開始されたかを継続的に問い合わせる
    • 実行中の workflow の artifact を監視する
    • artifact が見えたらダウンロードし、GITHUB_TOKEN を抽出する
    • 抽出したトークンで新しい branch を作成する
    • その branch に poc.txt という空ファイルを push する
    • その commit に新しい tag を作成する
  • artifact のサイズが約 21MB だったため、制限時間内に成功する可能性があると判断された
  • テスト用リポジトリで成功した後、github/codeql-action リポジトリに対して実行された
  • 約 2 時間後にワークフローが実行され、スクリプトはトークンを取得して branch 作成、file push、tag 作成に成功した

tag 改ざんが広げた影響範囲

  • 攻撃者はそのトークンで保護されていない branch に悪意あるコードを追加できた
  • よりステルス性の高い方法として、merge 前の feature branch に小さな悪意ある変更を入れ、merge を待つ戦略も可能だった
  • tag 作成権限も重要だった
    • 悪意あるコードを含む commit に v3 tag を付ければ、codeql-action@v3 を手動で使う利用者が悪意あるコードを実行する可能性があった
  • さらに大きな影響はデフォルトの CodeQL 設定から生じた
    • リポジトリ設定で CodeQL をデフォルト設定として有効にすると、リポジトリの workflow 一覧には表示されない特別な GitHub Actions workflow が実行される
    • この workflow はリポジトリの checkout、CodeQL 初期化、CodeQL scan、結果アップロードを行う
    • 内部的には github/codeql-action リポジトリの action を v3 tag が指す commit として実行していた
  • 当時の v3 tag は不変ではなく、GitHub が推奨する workflow pinning も使われていなかった
  • 攻撃者が侵害された GITHUB_TOKEN で v3 tag を悪意ある commit に移せば、デフォルトの CodeQL workflow を使うリポジトリが悪意ある CodeQL action を実行する可能性があった
  • CodeQL action は実行対象リポジトリのソースコードを checkout するため、悪意ある action は CodeQL デフォルト設定を使うリポジトリのソースコードを流出させ得た

GitHub Actions Cache poisoning 経路

  • デフォルトの CodeQL action の GITHUB_TOKEN は read 権限しか持たないため、デフォルト設定だけでは repository write 操作や release バックドア、workflow_dispatch による secrets 窃取をすぐには実行できなかった
  • その代わり、デフォルトの CodeQL action はリポジトリの main branch で実行される
  • GitHub リポジトリの main branch はリポジトリ全体で使われる cache entry を書き込めるため、GitHub Actions cache poisoning の機会が生じる
  • GitHub Actions Cache Poisoning は Adnan Khan の記事 で扱われた手法であり、Cacheract は cache poisoning を通じて build pipeline に永続性を残す malware である
  • 攻撃者が CodeQL workflow で Cacheract を展開すると、次の流れが可能だった
    • cache entry を予測する
    • その entry を悪意ある action で上書きする
    • actions/cache を使う workflow でコード実行を得る
    • その workflow の GitHub Actions secrets と高権限の GITHUB_TOKEN を窃取する
  • 悪意ある CodeQL action が発見されて脆弱性が対処されたとしても、Cacheract は cache poisoning を継続できた可能性がある
  • CodeQL と actions/cache を併用する主要リポジトリの例として、HomebrewAngularGrafana が確認された

CVE-2025-24362 と修正

  • この公開により CVE-2025-24362 が割り当てられた
  • 公開された GITHUB_TOKEN は、失敗した code scanning workflow の後に CodeQL Action がアップロードした debug artifact 内に含まれていた
  • CodeQL Actions リポジトリは意図的に失敗を発生させていたが、他の CodeQL Actions 利用者でも同様の失敗が起きていれば、workflow 環境変数を通じて自分たちの secrets を露出していた可能性があった
  • この問題は CodeQL Action 3.28.3 で修正された
  • 最大の潜在的影響は CVE 自体よりも、CodeQL Actions リポジトリに対して脆弱性を悪用し、CodeQL 利用者にサプライチェーン攻撃を仕掛ける経路にあった

GitHub の対応と推奨される緩和策

  • GitHub の対応スケジュールは次のとおりだった
    • 2025 年 1 月 22 日 15:13 UTC: GitHub に報告を提出
    • 2025 年 1 月 22 日 17:48 UTC: GitHub が受領を確認
    • 2025 年 1 月 22 日 18:28 UTC: GitHub が脆弱性を確認し、「PR Check – Debug artifacts after failure」workflow を一時的に無効化し、debug artifact アップロードを無効化する PR を提出
    • 2025 年 1 月 24 日: GitHub が CVE-2025-24362 を割り当て、security advisory を公開
  • GitHub Actions workflow artifact における secret 露出リスクを減らすための対策は次のとおり
    • workflow artifact には特定のファイルやディレクトリだけをアップロードする
    • 環境変数、.git/config、runner の <path_to_runner_dir>/_work/_temp/ ディレクトリ内ファイルを含む artifact のアップロードを避ける
    • GITHUB_TOKEN 権限を read-only に制限する
    • artifact アップロード前に secret scan を実行する

1件のコメント

 
GN⁺ 2025-04-01
Hacker Newsのコメント
  • GitHubがimmutable actionsをもっと早く推し進めていれば、こうした影響もはるかに小さかったはず
    この機能は現在のGitHub Actionsの攻撃対象領域の70%以上を防いでくれるはずだと、何度も繰り返し言い続けることになる。毎週のように事故が起きているのを見ると、そろそろリリースしてもよい頃だと思う
    [1] https://github.com/features/preview/immutable-actions

    • まだプレビュー状態なら、それ相応の理由がある可能性が高い。深刻なバグ、セキュリティホール、急ぐとより大きな被害を出しかねない互換性の破壊などがあり得る
  • この一時トークンが、新しいデプロイを作成し、アーティファクトの証明を生成する権限まで持っていた理由については説明がない
    修正としてデバッグログをオフにしたと言っていたが、コード分析エンジンに合わせて一時トークンの権限をより適切に変更したのかには答えていなかった

    • 誰もが知っている昔からの話のように思える。作っていたエンジニアが権限拒否に遭遇し、すべての権限を与え、その後最小権限に減らしに戻らなかったということ
    • GitHub Actionsの一時トークンにワークフローで定義した権限範囲がない場合、リポジトリ設定に応じて許可的なデフォルト範囲か制限的なデフォルト範囲が適用される。この設定は組織レベルでも、すべてのリポジトリを制限するよう構成できる
      以前はデフォルト値が許可的設定だけだったため、古い組織やリポジトリでは残念ながらこの設定が使われていることが多い
      新しいリポジトリを作ると上位組織のデフォルト値を継承するため、誰かが変更しなければ、この安全でないデフォルトが残り続ける。ユーザー全体の設定はないので、個人所有の新規リポジトリは制限的なデフォルト値を使う。新しく作成した組織も、より良いデフォルト値を使うと理解している
      [0]: https://docs.github.com/en/actions/security-for-github-actio...
    • 一時アクショントークンはデフォルトで全体の書き込み権限を持つ。読み取り専用版を使うには明示的に選択する必要がある

      Read and write permissions
      Workflows have read and write permissions in the repository for all scopes.
      ドキュメントのこの行(https://docs.github.com/en/actions/security-for-github-actio...)だけを読むと、違うように考えるかもしれない
      If the default permissions for the GITHUB_TOKEN are restrictive, you may have to elevate the permissions to allow some actions and commands to run successfully.
      しかし自分たちのGitHub組織では「Read and write permissions」がデフォルトで、だからあのドキュメントの文は筋が通らないと確認できる

    • 2023年のMicrosoftハッキングもこれに似ていた。CISAがセキュリティがひどいと公に叱責した事件だが、Microsoftが事件を説明するために投稿したブログ記事にも、答えられていない疑問があまりにも多かった
    • デバッグログをオフにしたのは、素早い暫定対応だったことを願う。最終的な修正であってはならない
  • CIとCDは完全に分離された環境であるべきだという確信がますます強まっている。CIが侵害されたからといって、CD関連のトークンが流出してはいけない

    • この分野には個人的に非常に関心があるが、解決策はCDを別の小さな特殊システムとして切り離すことよりも、CDを多要素のようにする方向だと思う
      たとえば "sub":"repo:octo-org/octo-repo:environment:prod"[1] のような条件を必ず満たすようにし、システムをさらに堅牢にしたければ他の[楽しいclaims][]も追加すればよい
      1: https://docs.github.com/en/actions/security-for-github-actio...
      fun claims: https://github.com/github/actions-oidc-debugger#readme
    • 本質的には、これが職務と関心事の分離の見え方だ。良いプロジェクト事例でもこのように動作しているものがある。具体的な手法、ツール、CIとCDの境界は最終成果物の性質によって変わるが、概念的には完全に正しい
  • 対応時間は冗談ではなかった。GitHubの対応はかなり印象的だ

    • 全体の書き込み権限がある公開トークンが露出したのは、あまり印象的ではない
  • Praterという姓を持つ立場として、この名前がPraetorianに由来するので、praetorian.comを持っていたら本当に良かったと思う

    • そのためには、1995年の映画『The Net』が公開される前にその考えに至っている必要があった
    • 彼らのgokartプロジェクトは素晴らしかった
  • 公開GitHub Actionsを使うのは自ら問題を招く行為であり、ワークフロー手順を分析していないならなおさらだ
    むしろwoodpeckerやその他の優れたCIビルダー(circle、travis、gitlabなど)を自前でホスティングする方がよい

  • OpenZFSのPRにCodeQLを適用しておいた。これはOpenZFSにとっては問題ではない。私たちのコードは秘密ではないからだ :)

    • コードが秘密でなくても、良い判断だとは思わない。攻撃者がコードやリリースアーティファクトに何でも追加できたからだ
      それでも少なくとも迅速に解決されたのは幸いだ
  • これは修正されたのか?

    • 記事とここのコメントにある通り、その通り。1月に報告された後、GitHubが3時間以内に緩和措置を取った
  • このサイトは性能が悪すぎて、スクロールもほとんどできない