世界を動かす技術を、日本語で。

GitHub Actionsは最も弱いリンクです

概要

  • 近年のオープンソースサプライチェーン攻撃は GitHub Actionsワークフロー の脆弱性に集中。
  • pull_request_targetやissue_commentなどの 危険なトリガー が多用されている現状。
  • キャッシュ汚染、タグの不変性欠如、過剰な権限 などが共通要因。
  • セキュリティ対策は 一部オプトイン であり、デフォルトの安全性が不足。
  • zizmor 等の外部ツール利用やワークフロー見直しが急務。

近年のオープンソースサプライチェーン攻撃の実態

  • ほぼ全ての事例で .github/workflowsのYAMLファイル が攻撃の起点。
  • UltralyticsによるPyPIへの 仮想通貨マイナー混入、nxパッケージの 資格情報窃取 化、tj-actions経由での 23,000リポジトリの秘密漏洩、Trivyの 短期間での二度の侵害、elementary-dataの コメント経由マルウェア公開 など、多様な攻撃例。
    • 各事例で GitHub Actionsの仕様通りの挙動 が悪用。
  • uses: 行 が毎回可変タグを解決することで、 依存性の固定や検証が困難
  • ワークフローの多くが プライベートCI前提の安全設計 のまま、公開リポジトリやフォークでも利用されている状況。

主なインシデントの流れと特徴

  • 2024年11月のspotbugs事件
    • pull_request_target トリガーで 信頼されないフォークのコード をビルド・実行。
    • PAT流出 が後のtj-actions/changed-files侵害につながる。
  • Ultralytics事件
    • pull_request_targetで キャッシュ汚染、後続のリリースワークフローで マルウェア実行
  • tj-actions事件(2025年3月)
    • mutableタグ を利用した 間接依存関係の乗っ取り
    • 23,000リポジトリが 秘密情報を漏洩
  • s1ngularity事件(nx)
    • PRタイトルのテンプレート展開 経由で コードインジェクション、npmトークン悪用。
  • Trivy事件
    • pull_request_targetワークフローの 設定ミス複数回侵害
    • 過去バージョンのタグ書き換え による“安全なバージョン”の裏切り。
  • elementary-data事件
    • issue_commentトリガー$展開 による bash実行 で即座に PyPIへマルウェア公開

共通する要因

  • pull_request_targetissue_comment など、 未検証イベントでフル権限ワークフロー実行
  • シェルスクリプトの$展開 による 無検証テキスト挿入
  • GITHUB_TOKENのデフォルト権限 (2023年2月以前作成リポジトリはwrite)。
  • アクションのバージョン管理がmutableなgit ref、タグ書き換えが容易。
  • キャッシュの信頼境界を超えた共有

GitHubの対応と課題

  • セキュリティロードマップ 発表(2024年)
    • ワークフローロックファイルpull_request_targetの禁止ポリシーワークフロー単位のシークレットスコープegressファイアウォール などを計画。
    • すべて オプトイン公開まで数か月のプレビュー既存ワークフローの互換性重視
  • 既存の危険なデフォルト が温存されており、 長期的なリスク が継続。

効果的な対策

  • zizmor 等の サードパーティ製リンター 活用。
    • 4行程度のYAML追加で 危険なワークフローの自動検出
  • pull_request_targetやissue_commentの利用見直し明示的なpermissions:ブロック の設定。
  • uses: のSHA固定外部アクションの信頼性検証
  • キャッシュの書き込み制御と信頼境界の明確化
  • 必要なら GitHub Actionsからの移行 も検討。

Trusted Publishingの現状とリスク

  • PyPI, npm, RubyGems, crates.io等が OIDCベースのTrusted Publishing を採用。
    • 長期APIトークンのリポジトリ内保存を避けられる利点。
  • ワークフローの安全性がパッケージ配布の根幹に
    • GitHub Actionsの脆弱性がサプライチェーン全体のリスク へ直結。
  • OIDC連携の大半がGitHub Actions 経由で実施されている現状。

今後の展望と提言

  • セキュア・バイ・デフォルト な設計への転換が急務。
  • オプトイン方式ではなく、危険なデフォルトの見直し が必要。
  • 既存のワークフロー破壊を恐れず、安全性を最優先 する判断。
  • 外部ツールによる監査・自動検出プラットフォーム自体の改善 の両輪推進が重要。

Hackerたちの意見

LLMがセキュリティ面で持ってくるべきことって、ほんとこれだよね。今はメンテナンスする側が修正しやすくなったから、問題を早く見つけられるようになった。もちろん、これにはデメリットもあって、「最近はすぐに腐る」っていうトロープにさらに進んでしまうけど、脅威が常に進化している敵対的な世界にいるから仕方ないよね。明日(今日)、サーバーやリポジトリはもうスクリプトでスキャンされるんじゃなくて、もっと多くのセキュリティ問題を知っているモデルによってスキャンされるようになるだろうね。

GitHub Actions、今はめっちゃ遅いよ。うちの会社がクラウドやプライベートのGitHubランナーにお金をたくさん払ってるのにね。みんなが叩きやすい対象なのは分かるけど、GitHubの大部分でCopilotレビューをグローバルに有効にするのはちょっと早すぎたと思う。セキュリティの問題はさておき、これが続くと、GitHub Actionsからコードを出荷したりデプロイしたりできなくなるかも。もしかしたら、JenkinsやTravis CIに戻らなきゃいけなくなるかもね。

恥ずかしながら宣伝だけど、RWXをチェックしてみて!(rwx.com)

GitHub Actionsが最初に出たとき、uses:の行ではタグじゃなくてコミットハッシュを使ってたんだ。何人かの同僚は、タグの方が安全だって反対してたけど、最終的には「まあ、actions/checkoutみたいな有名なアクションなら大丈夫だよね。もしそれが侵害されたら、数分でニュースになるだろうし」って言ったんだ。でも、サードパーティのアクションについてはコミットハッシュを使い続けた。今はその選択が正しかったと思ってる。SHAの衝突でサプライチェーン攻撃を受ける可能性はまだ少しあるし、NPMの依存関係を通じて攻撃される可能性の方がはるかに高いけど、uses:の行でコミットハッシュを使ってないなら、今すぐ切り替えた方がいいよ。もしメジャーバージョンだけのタグ(例えばv5)を使ってるなら、今すぐ切り替えた方がいい。v5.2.3のタグで侵害されたバージョンがアップロードされる前にね。

SHAの衝突攻撃の現実的なリスクはないよ。NPMの依存関係を通じてサプライチェーン攻撃を受ける可能性の方がずっと高い。アクションの作成者たちもハッシュを固定してくれてるといいけどね。

今の職場でRenovator(EDIT: Renovate)を使ってるのがすごく嬉しい。デフォルトでSHAに変更するPRを上げてくれるからね。将来のPRでバージョンを上げるときも、SHAを上げてくれるし、どのタグバージョンを表しているかのコメントもつけてくれる。

GitHub Actionsにはロックファイルがないから、SHAでロックされたアクションを使ってても、他のタグのコンポジットアクションを使っていると、将来的にそれが侵害される可能性があるから、依然としてトランジティブ攻撃にさらされるよ。

自分のアクション内でのピン留めだけじゃ不十分だってことは覚えておいて。コンポジットアクションが可変参照(アクション、Dockerイメージなど)を使っていないことも確認する必要があるよ。

組織レベルでハッシュにピン留めされたアクションだけを許可するように強制できるよ。許可するアクションの小さなホワイトリストを選ぶこともできる。

でも、デメリットもあるよね。 - 脆弱性アラートを失う - メンテナンスの負担が増える - Immutable Releasesが広まったら、価値がゼロになるリスクを抱えることになる。これについていくつかブログを書いたよ。対策のための仮の方法もね。 https://developerwithacat.com/blog/202604/github-actions-sup...

SHAピンニングでも、1ホップしか進めないんだよね。もしピン留めされたアクションが、他のピン留めされてないアクションを使ってたら、やっぱり危険だよ。完全なネストツリーを指定するための高レベルな方法がないと、この問題は解決できないと思う。初めてアクションが実行されたときのTOFUみたいな感じ(その実行時点で全ての子をピン留めする)なら改善になるかもしれないけど、それでも後からアクションを変更するタイムド攻撃に対しては脆弱だよね(文字通り、時間がXを超えたら…みたいな)。

YAMLでプログラミングするのは、ずっとクレイジーだと思ってた。アクションは、シンプルな混合命令型/宣言型スクリプト言語(js拡張とか)を作るのにぴったりな場所に見える。しっかりした計測可能でデバッグ可能なランタイムと、ローカルでモックインフラに対して実行できるOO APIがあればいいのに。

いらないよ、Jenkinsは3つのDSL言語があって、どれも良くないし。yamlにインラインコードを書く必要なんてないよ。スクリプトを呼び出せばいいんだから、そのスクリプトは好きな言語で書けばいいし。

YAMLが問題じゃないんだ。すべてのアクションが基本的にcurl-to-sudo-bashになってるのが問題。セキュリティの観点を無視しても、使い勝手が本当にひどい。Azure DevOpsでもそうだったし、GitHub Actionsでも同じだよ。悪いインターフェース、驚くような挙動、全部揃ってる。CIはシェルコマンドだけで構成されるべきだよ。抽象化もサプライズもなしで。(PowerShellは別だけど、あそこは驚きの原則が支配してるからね。)

YAMLよりも、コードをテストしてデバッグするためのまともなツールがない方がよっぽど気になる。

IaCにPulumiを試したけど、あまり好きじゃない。Pulumi自体は素晴らしいけど、コンセプトがあまり好きじゃないんだ。開発者にとっては迷宮みたいなもので、YAMLだとKISSを強いられるところに複雑さを許してしまう。

ちょっと宣伝になっちゃうけど、許してね。ここ5年間、CIをブラックボックスのプラットフォームや独自のDSLに閉じ込めないことの重要性を警告してきたんだ。その間に、オープンでプログラム可能なプラットフォームとしてCIを再発明する旅をしてきた。正直、まだ進行中なんだけど、再発明って難しいんだよね!でも、もし30年のレガシーを脱ぎ捨てたときのCIの姿を見たいなら、Daggerをチェックしてみてね(https://dagger.io)。それとも、特定の製品を使うことにコミットせずに、同じような考えを持つシステムエンジニアたちとCIの未来について話したいなら、私たちのDiscordに参加してみて(https://discord.com/invite/dagger-io)。

かっこいいね。セルフホスティングできるの?つまり、自分のセルフホスティングのforgejoインスタンスの隣にホストできるのかな?

ちょっと前にこれを見たとき、ホームページが「AIハイプ」トレンドに乗ってる感じだったんだよね。なんか「自律エージェントのためのAIネイティブXYZ」みたいな。今はそんな感じじゃないけど、誰かと勘違いしてるのかな?それとも方針を変えたの?

謝る必要はないよ。難しい問題に対するストレートな解決策の提案、感謝してる。

採用してるの?これ、めっちゃ面白そうな分野とプロダクトだね。

いい記事だね。ただ、遷移的アクションのためのロックファイルがないことと、静的解析だけに頼るのは厳しいよね。zizmorみたいなリンターは素晴らしいけど、深いコンポジットアクションツリーやランタイムテンプレートインジェクションには苦労してる。セキュリティの欠如にフラストレーションを感じて、自分でGHA用のオープンソースランタイムサンドボックスに取り組み始めたんだ: https://github.com/electricapp/hasp 最初のチェックはtrivy攻撃に触発されたもの。haspはSHAピン留めを強制し、コメント(# v4.1.2)が実際に前のSHAに解決されるかを確認する。これがさらに大きなチェックのスイートに成長したんだ。ただ静的にYAMLを解析するだけじゃなくて、ランナー環境自体にフックするんだ。いくつかのランタイムチェックは、zizmorがすでにやっていることを反映していて、上流SHAを標準ブランチに解決したり(偽のコミットはなし)、遷移的依存関係ツリーをたどったりする。ここに比較ドキュメントを持ってPRを出してるよ(hasp vs. zizmor): https://github.com/electricapp/hasp/pull/13/changes#diff-aab... さらに、サンドボックス化して、ランタイムでシークレットを注入するトークンブローカーとして機能することで、敏感な情報の流出を防いでる。GHトークンはGH APIを呼び出すためだけに使えるんだ。Rustを使ってlandlock、seccomp、eBPFを利用してるから、Dockerは使ってないよ。トークンブローカーサンドボックスは、一般的な実行可能ファイルをラップするためにも使えるから、GHA以外の文脈でも一般的に適用できるんだ(つまり、エージェンティックや他の文脈で、トークンのランタイムインジェクションが流行ってるみたい)。これはGHがロードマップのいくつかの機能を展開するまでのつなぎとして使ってる。ランナーをゼロトラストまたは悪意のある環境として扱う方向に進んでるから、これがその方面での私の小さな貢献なんだ。

そうだね!まだGithubからは移行してないけど、そろそろ考え始めてる。もし同じような状況なら、私たちが使ってる便利なツールを紹介するよ: - https://github.com/sethvargo/ratchet で外部アクション/ワークフローを特定のコミットハッシュにピン留め - https://www.warpbuild.com/ でより速いランナーを使う(他にも、runs-on/namespace/buildjet/blacksmith/depot/... 好きなのを選んで) - もうすぐBuildkiteに移行してCIジョブのオーケストレーションをする予定。まだ「Gitリポジトリを保存して、PRを作成・マージできる」部分の合理的な代替が必要なんだ。Pierreチームが公開してるすべてのピースを誰かがまとめて、早く提供してくれるといいな。GithubのUIとgh CLIは実際にすごく良いし、既存の代替コードストレージツールはあまり良くないと思う。

他の選択肢よりwarpbuildを選ぶ理由は何?depotは前に見たことがあって気になってるけど、他のプラットフォームにもオープンだよ。

個人的にはGitHub Actionsはあまり好きじゃないな。制御外の依存関係があるし、デバッグが面倒だから。大抵の時は、この巨大なスクリプトをいじってる感じで、うまくいくことを祈って息を潜めてる。だけど、使う理由は、Windows、macOS、Linuxの3つのプラットフォームのビルドサーバーを自分で維持するのが面倒だから。特に、たまにしかビルドされないプロジェクトの場合はね。これが面倒な理由の一つは、同じホストでWindowsとLinuxのVMを簡単に動かせるのに対して、macOSは特別なユニコーンみたいで、専用のマシンが必要になるかもしれないから。 (でも、それを除いても、毎日使わないマシンを維持するのは面倒になることがあるよね。)

うちはGHAをシンプルな呼び出しとして使ってて、すべてnixスクリプトでコーディングしてる。このやり方の一番の利点は、自分のマシンからCIを直接呼び出せて、同じように動くところだね。

ジョン・ハワード(Istioのメンテナーの一人で、現在はSolo.ioに所属)が「Blacksmithを使った高速GitHub Actions」についてブログを書いてるよ。[1] そのブログには「GitHub Action Runnerの代替案」へのリンクもあるよ。[1]: https://blog.howardjohn.info/posts/blacksmith-gha/ [2]: https://binhong.me/blog/github-action-runner-alternatives/