電通総研 テックブログ

電通総研が運営する技術ブログ

GitHub Actions の更新への追随とリスク低減のバランスを考える

こんにちは。コーポレート本部 サイバーセキュリティ推進部の耿です。

2025年3月に tj-actionsreviewdog など有名なサードパーティアクションを巻き込んだサプライチェーン攻撃が発生しました。GitHubGitHub Actions の仕様を熟知したうえで悪用した、非常に巧妙な攻撃手法です。 (詳細

GitHub Actions の action の利用は、自組織のGitHubリポジトリで第三者が書いたコードの実行を許すことに他なりません。その便利さと引き換えに一定のセキュリティリスクを孕んでいることを意識し、正しく対策を考えることが重要です。

今回発生したような侵害への防止策として、GitHub Actions の action を利用する場合のバージョン指定はバージョンタグではなく、フルコミットハッシュ(SHA)を利用して「ピン留め」すること(参考)が、より一層推奨されるようになっています。Gitのコミットハッシュは、リポジトリ内のオブジェクトを階層的に SHA-1 ハッシュ化したものなので、コードが書き換わるとコミットハッシュも勝手に変わります。つまりコミットハッシュでバージョン指定することにより、実行されるコードを事実上固定することができます。
しかし、コミットハッシュによるバージョン指定だけで話を終えるのは不十分です。運用まで考えたときに、コミットハッシュで指定したバージョンの更新方法にも気を配らないと、全くリスク低減にならない可能性があります。GitHub Actions の action をバージョン更新する際の運用負荷とセキュリティリスク低減のバランスについて考えてみます。

(おさらい)フルコミットハッシュ(SHA)によるバージョン指定

様々なところで言われていることなので詳細は省きますが、GitHub Actions の action に付けられたGitタグは書き換え可能なので、バージョンタグでバージョン指定すると、実行されるコードは可変です。

      - uses: actions/checkout@v4

アクションのREADMEや技術記事などでバージョンタグによる例が記載されていても、自分で利用するときにはフルコミットハッシュに書き換えるようにしましょう。

      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

バージョン更新の課題

フルコミットハッシュでバージョン指定をしても解決されない課題があります。どのようにバージョン更新を行うかという課題です。
特に多くの GitHub Actions の action を使っている場合や、多くのリポジトリを管理している場合は、バージョンの更新を手作業で実施するのは手間がかかります。手間を減らすために、Dependabot や Renovate を利用して更新を自動化することがよく行われています。(Dependabot と Renovate は、フルコミットハッシュでバージョン指定していても更新のPRを作成できます。)

ここで留意しておきたいのは、更新を自動化することにより、新しいバージョンが侵害されていた場合には影響を受けやすくなってしまうということです。今回 tj-actions/changed-files が侵害を受けた件でも、バージョンタグが(悪意のあるコミットを指すように)更新されたことを検知し、多くのリポジトリで動いている Renovate がバージョン更新の PR を出していました(参考)。さらに、GitHub Actions のワークフローでよく使われる pushイベントトリガーでは、更新されたブランチ(つまり更新された新しいバージョン)のワークフローファイルが実行されます。つまり自動作成された PR をマージせずとも、PR が自動作成されただけで侵害されたバージョンが自分のリポジトリ上で実行される可能性があるということです。

まとめると、以下の攻撃が成立し得ます:

  1. 利用している GitHub Actions の action が侵害され、リリースされる。あるいは更新された新しいバージョンに脆弱性が含まれる
  2. DependabotやRenovateがバージョン更新を検知し、PRを作る
  3. push イベントをトリガーに実行されるワークフローでは新しいバージョン(侵害されたバージョン or 脆弱性のあるバージョン)の GitHub Actions の action が実行する
  4. 自分のリポジトリが被害を受ける

GitHub Actions の action の更新の自動化には気を遣わなければならないと考えています。

解決策1:セキュリティアップデート以外は更新を自動化しない

自動化せずにアップデートを手作業で行えばリスクは低減できますが、運用負荷が上がってしまいます。
特に GitHub Actions のセキュリティアップデートを自動化しない場合、対応までの時間が伸びてしまいます。
両者のバランスを考えたときに、(一定のセキュリティリスクが発生することを承知の上で)「セキュリティアップデートのみを自動化し、それ以外のアップデートは自動化しない」方針が考えられます。

セキュリティアップデートのみの自動化は次の方法で実現できます。

  • Dependabotの場合
    • Dependabot Version UpdatesではなくDependabot Security Updatesを利用する
  • Renovateの場合

セキュリティアップデート以外を自動化せずに更新する部分については、完全に手作業でコミットハッシュをコピー&ペーストしていくのは大変なので、ローカルツールの pinact などでコミットハッシュを更新するのも良いでしょう。

解決策2:セキュリティアップデート以外は自動更新を一定期間待機する

Renovateには、セキュリティアップデート以外の更新をすぐにせずに指定期間待機してからPRを作成する機能があります。一定期間待機することで、その間に攻撃や脆弱性が検知・解決されることを期待するという考え方です。

Dependabot Version Updatesにも、最近のアップデートで同じような機能がベータ版として出ています。ただし現時点ではまだGitHub Actionsはサポートされていないようです。使えるようになったら試してみたいと思います。

(2025/7/10追記)Dependabotのcooldownパラメータが正式リリースされましたので、解説記事を公開しました。

自動更新の待機期間をどれぐらいにするべきなのか?

これは答えが出ない問題です。
GitHub Actions の action による悪さを「100%」回避するには次のどちらかしかないと思っています。

  1. GitHub Actions の action をそもそも利用しない
    • GitHubの公式 action(actions/checkout など)が侵害されるリスクも考慮し、利用しないとすると、「GitHub ActionsによるCI/CDを実施しない」こととほぼ同義になると思います
  2. GitHub Actions の action のバージョン更新をするときに「コードの内容を全て読み」、「動きを完全に理解」したうえで更新する

このどちらも現実的ではないのは明らかです。GitHub Actions の action を利用することの便利さを享受するには、一定のリスクを受容するしかないと考えています。待機期間の判断も同じです。今回の侵害の件では tj-actions に対する侵害は数日で対応されましたが、 reviewdog に対する侵害の対応には1週間以上かかったようです。どれぐらいの期間を置けば侵害や脆弱性が検知され、受容できる程度までリスクが低減するかは程度問題でしかありません。リポジトリの重要度と運用の手間で判断することになるでしょう。
それでもあえて個人的な考えを述べるならば、1週間程度は少なくとも待ちたい気持ちがあります。(根拠はなく、ただの個人的な感覚であることを強調しておきます。)

お読みいただきありがとうございました。

私たちは一緒に働いてくれる仲間を募集しています!

電通総研 キャリア採用サイト

執筆:@kou.kinyo、レビュー:@nakamura.toshihiro
Shodoで執筆されました