- GitHub Actionsはワークフローファイルの
uses:構文を通じてパッケージ依存関係を宣言して実行する構造を持ち、これは実質的にパッケージマネージャーとして機能する
- ただし、ロックファイル(lockfile)、整合性ハッシュ、トランジティブ依存関係の固定、依存関係ツリーの可視性など、他のパッケージマネージャが標準で提供する機能が一切ない
- 調査結果、ほとんどのGitHub Actionsユーザーが未検証の外部コードを実行しており、コードインジェクション脆弱性が数千件のワークフローで発見された
- GitHubは不変リリースやSHA固定ポリシーなど一部の緩和策を導入したが、トランジティブ依存性や再現性の問題は依然として解決されていない
- この構造的欠陥はソフトウェアサプライチェーンのセキュリティ全体に影響を及ぼし、GitHub Actionsを基盤とする他のCIシステムにも同じ問題が拡散する
GitHub Actionsのパッケージ管理構造と問題点
uses: actions/checkout@v4のような構文は依存性宣言であり、GitHubがこれを解釈してダウンロードおよび実行する
- これは一般的なパッケージ管理の挙動と同じだが、ロックファイルがないため実行ごとに異なるバージョンが選択されうる
- 他のパッケージマネージャ(npm、Cargo、NuGetなど)と比較すると、Actionsはロックファイル、トランジティブピンニング、整合性検証、依存関係ツリーの可視性、解決仕様をすべて欠いている
- ロックファイルの欠如が核心的な問題であり、実行時ごとに依存性解決が異なるため非決定的ビルドが発生する
セキュリティ研究結果と脆弱性
- USENIX Security 2022の研究によれば、99.7%のリポジトリが外部開発者のActionsを実行しており、97%は未検証の作成者、18%はセキュリティ更新の欠落状態
- 続報では、2.7百万件のワークフローのうち4,300件以上でコードインジェクション脆弱性が発見された
- GitHub Actionsは、admittance control、execution control、code control、secretsアクセス制御などCI/CDに不可欠なセキュリティ属性を十分に提供していない
主要な技術的欠陥
- 可変バージョンの問題:
@v4のようなタグはメンテナーが新しいコミットで再タグ付けできるため、コードが静かに変更される
- ロックファイルがあれば、そのタグがどのSHAとして解釈されたかを記録可能
- トランジティブ依存性の不透明性: Composite Action内で呼び出される他のActionは見えず制御も不可
- 調査によると、JavaScript Actionsの54%がセキュリティ欠陥を含み、そのほとんどが間接依存性から発生している
tj-actions/changed-files事例では、トランジティブ依存性の更新を介して機密情報漏えい攻撃が発生した
- 整合性検証の欠如: npmやCargoではハッシュを記録してダウンロード検証を行うが、ActionsはSHAベースの信頼のみに依存
- 再実行の非再現性: GitHub側は「バージョンが強制プッシュされると最新バージョンを取得する」と明記しており、同じワークフローでも異なるコードが実行され得る
- 依存関係ツリーの非可視性: npmの
npm lsやCargoのcargo treeのような機能がないため、全体の依存構造を確認する方法がない
- 解決ルールの非公開: Actionsの依存性解決は文書化されておらず、
ActionManager.csのコードには単純な再帰ダウンロードロジックしかない
追加の構造的制約
- セントラルレジストリの欠如: ActionsはGitリポジトリ上に存在するため、セキュリティスキャン・マルウェア検出・タイポスカッティング対策機能がない
- 共有環境の問題: 複数のActionが同一の
$PATHを変更することで、実行順序によって結果が変わる
- オフライン実行不可: GitHubから毎回ダウンロードしなければならず、ネットワークがない状態では実行できない
- ネームスペースの脆弱性: GitHubユーザー名がそのままネームスペースとなるため、アカウント乗っ取りやタイプミス攻撃にさらされる
- ロックファイルと整合性ハッシュがあれば、コード変更時にビルド失敗として検出可能
設計背景と波及効果
- Actionsランナーは本来Azure DevOpsベースで、内部的に信頼された環境を前提に設計されていた
- GitHubがこれを公開マーケットプレイスとして拡張した際に信頼モデルを再設計しなかった
- その結果、ロックファイル、整合性検証、トランジティブピンニング、依存性可視性といった基本的な機能が欠落
- OIDCベースのパッケージ自動配信機能が普及するにつれ、Actionsのセキュリティ欠陥がパッケージレジストリ全体のサプライチェーンセキュリティに影響
- GitLab CIは
integrityキーワードを導入しハッシュ検証をサポートする一方、GitHubは同じ要求を「計画なし」として終了した
- Forgejo ActionsなどのGitHub互換CIシステムも同じ構造を維持せざるを得ないため、欠陥がエコシステム全体に拡散する
改善提案と現状
- コミュニティは**ロックファイル対応(issue #2195)**を要望したが、GitHubは2022年に「計画なし」としてクローズした
- Palo Altoの研究はSHA固定のみではトランジティブ依存性の保護が不可能であることを実証した
- 一部のチームはDependabotによる更新、自己リポジトリベンダリング、zizmorセキュリティスキャナなどで補完している
- 根本的な解決策は、すべてのActionとトランジティブ依存性のSHAと整合性ハッシュを記録するロックファイルを導入すること
- GitHubがこれを採用しない限り、CI/CDサプライチェーンの信頼性確保は不可能
2件のコメント
痛い目に遭わないと目が覚めないんでしょうね。
Hacker Newsの意見
GHA(GitHub Actions)を擁護したいわけではないが、ドキュメントには安定性とセキュリティのためにコミットSHAへの固定を推奨すると明記されている。
lockファイルのように自前で実装することはできるが、transitive dependencyは制御不能なので完全ではない。
結局、セキュリティパッチの追跡とハッシュ更新の負担が生じ、このためハッシュベースの固定は広く使われていないように思える。
ほとんどのユーザーは問題を認識しておらず、認識している人でもSHAはほとんど使っていない。
私個人はActionsが好きでいくつかメンテナンスもしているが、公開リポジトリを見ると90%が
@v1、9%が@v1.2、コミットSHAを使っているのは1%だけだ。GitHubが少し投資するだけでlockファイルソリューションを作れたはずだ。
しばしば特定のNodeバージョンやAPIバージョンに依存するため、むしろ**@main**を使ったほうがよかった経験もある。
「固定されたバージョン」を得ていると錯覚するが、実際にはそうではない。
2回問題を経験してようやく気づいた――lockファイルがあるか、ないかのどちらかだ。
GitHubは自前のActionsをほとんどメンテナンスしておらず、基本機能ですら非公式フォークに依存するようになっている。
エコシステム全体がその場しのぎで維持されている印象だ。
GitHubが機能開発よりもAzure移行を優先すると発表したからだ。
関連記事
うちの小規模な会社でも毎月200ドル以上払っている。
WindowsよりもGitHubサブスクリプションのほうが重要な新たな収益源と見なされているようだ。
おそらく元の作者たちはすでに会社を去ったのだろう。
ArgoCDをCIパイプラインとして使ってみた人はいるだろうか。
GHAは「less is more」哲学の失敗例だと思う。
業界標準になってしまったのが最大の問題だ。
少し投資するだけでもっと良いCIを作れたはずなのに、MSがIE6時代の失敗を繰り返したように感じる。
今では比較対象を知らない若いエンジニア世代が、その限界を認識していない。
私は引退したノートPCをWoodpeckerサーバーとして動かしてみるつもりだ。人々が嫌わないCIとはどんなものか気になる。
GHAはそれに比べて大した価値がないように思える。
会社がJenkins/AnsibleからGHAへ移行しようとしたとき反対したが、今となっては正しい判断だった気がする。
CIは常にメンテナンス負担が大きく、とくにMac環境はいまだに扱いづらい。
「GitHubが正しいSHAコードを提供すると信じるのか?」という問いに対しては、
ほとんどの人がGitHubホスト型ランナーを使っている現実を見れば、それを信じられないならすでにもっと大きな問題を抱えていることになる。
もしGitHub Actionsが**ローカルファースト(local-first)**な構造で、**Nixベースのロック(locking)**をサポートしていたらどうだろう、と考えることがある。
cachix/cloud.devenv.sh
多くのサードパーティActionsが、ドキュメントやサンプルでmasterブランチを直接参照している。
悪意あるプッシュが一度行われるだけで、多数のリポジトリからデータ流出が起こり得る。
タグを使っても移動可能なので、完全な防御にはならない。
研究者たちが述べたCI/CDの4つの中核的なセキュリティ特性(認証、実行、コード、秘密情報へのアクセス)を見て疑問に思った。
CI/CDは本当に**秘密情報(secrets)**にアクセスする必要があるのだろうか?
API呼び出し権限だけで十分だと思う。
理想的なシステムは秘密情報を直接扱わず、セキュアエンクレーブのようなアダプターを通じて間接的に処理すべきだ。
現実には顧客の大半が依然として秘密情報を必要としている。
プラットフォームは少なくとも安全な秘密情報管理メカニズムを提供すべきだ。
とくにオープンソースプロジェクトはCIから直接デプロイしたいからだ。
「セキュアエンクレーブ方式」が具体的にどう違うのか気になる。
現実には環境ごとに異なり実装コストも大きいため、多くはコンテナ + 環境変数方式に落ち着いている。
こうしたテストを自動化するには秘密情報は避けられない。
lockファイルをリポジトリにコミットしなければならないなら、最初の生成時点でブートストラップ問題が生じる。
これを解決するには、Actionsをローカルで実行できる機能が必要だ。
nektos/act のようなツールもあるが、これは主にデバッグ用だ。
おそらく静的解析ベースの別メカニズムが必要になるだろう。