GitHub Actionsのサプライチェーン攻撃を防ぐ!アクションをコミットハッシュで固定する方法

目次

あなたのワークフロー、`@v4`で指定してませんか?

GitHub Actionsでこんな書き方、していませんか?

- uses: actions/checkout@v4
- uses: actions/setup-node@v4

公式ドキュメントでもこの書き方が載っているし、動いているから問題ないと思いますよね。でも実は、この@v4という指定はセキュリティ的に危険です。2025年3月に実際に起きたtj-actions/changed-files事件では、この仕組みが悪用され、23,000以上のリポジトリのCI/CDシークレットが漏洩するリスクにさらされました。

本記事では、タグ指定が危険な理由と、コミットハッシュで固定する具体的な方法を解説します。

`actions/checkout@v4`の裏側で何が起きているか

まず、@v4が何を意味しているかを理解しましょう。

GitHub Actionsのusesで指定する@以降は、Gitのref(参照)です。ブランチ名、タグ名、コミットハッシュのいずれかを指定できます。

# タグ指定(よく見る書き方)
- uses: actions/checkout@v4

# ブランチ指定(非推奨)
- uses: actions/checkout@main

# コミットハッシュ指定(最も安全)
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

ここで重要なのは、Gitのタグは「書き換え可能」だということ。タグは特定のコミットに貼るラベルに過ぎず、リポジトリの管理者(あるいは管理者権限を奪った攻撃者)はいつでも同じタグ名を別のコミットに貼り直せます

【タグ指定の落とし穴】

昨日: v4 → コミットA(正常なコード)
今日: v4 → コミットB(攻撃者が差し替えたコード)← 同じ「v4」なのに中身が違う!

あなたのワークフローは「v4」を信頼して実行
→ 攻撃者のコードが本番CIで動く

一方、コミットハッシュは改ざんできません。SHA-1ハッシュはコミットの内容から一意に決まるため、同じハッシュで中身を変えることは事実上不可能です。

実際に起きた:tj-actions/changed-files事件

2025年3月14日、GitHub Actionsで広く使われていたtj-actions/changed-files(プルリクエストの変更ファイルを検出するアクション)が侵害されました(CVE-2025-30066)。

何が起きたかを時系列で整理します。

  1. 攻撃者がリポジトリの書き込み権限を持つGitHubトークンを取得
  2. 正規のメンテナンスbot(renovate[bot])を装って、悪意のあるコミットをpush
  3. そのコミットに既存のバージョンタグ(v4等)を貼り替え
  4. @v4で指定していた全リポジトリのワークフローで、悪意のあるコードが実行される
  5. 攻撃コードはCIランナーのメモリ上のシークレット(APIキー、トークン、RSAキー等)をビルドログに出力

23,000以上のリポジトリがこのアクションを利用しており、パブリックリポジトリのビルドログは誰でも閲覧できるため、シークレットが大規模に露出するリスクがありました。

この事件の教訓は明確です。タグは信頼の根拠にならない。コミットハッシュで固定していれば、タグが書き換えられても影響を受けなかった

コミットハッシュで固定する方法

Step 1:使用中のアクションのコミットハッシュを調べる

アクションのGitHubリポジトリで、使いたいバージョンタグに対応するコミットハッシュを確認します。

# actions/checkoutのv4タグが指すコミットハッシュを確認
git ls-remote --tags https://github.com/actions/checkout.git | grep 'v4$'
# → 11bd71901bbe5b1630ceea73d27597364c9af683  refs/tags/v4

または、GitHubのリポジトリページでタグを選択し、コミットハッシュ(フルSHA)をコピーする方法でもOKです。

Step 2:ワークフローを書き換える

# ❌ Before: タグ指定(書き換え可能)
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/cache@v4

# ✅ After: コミットハッシュ固定(改ざん不可)+ コメントでバージョン明記
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.0

ポイントは、ハッシュの末尾にコメントでバージョンを書いておくこと。ハッシュだけだと何のバージョンか分からなくなるので、# v4.2.2のように添えるのがベストプラクティスです。

Step 3:既存ワークフローを一括変換する

手動でハッシュを調べるのが面倒な場合は、pin-github-actionというCLIツールで一括変換できます。

# pin-github-actionのインストール
npm install -g pin-github-action

# ワークフローファイルを一括変換
pin-github-action .github/workflows/ci.yml

実行すると、タグ指定をコミットハッシュに自動変換し、コメントにバージョンを残してくれます。

Dependabotで自動更新する仕組み

「ハッシュで固定したら、新しいバージョンが出た時に手動で更新するの?」という疑問が出ますよね。ここはDependabotに任せましょう。

リポジトリのルートに以下のファイルを追加するだけで、GitHub Actionsのアクション更新をDependabotが自動でPRしてくれます。

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

Dependabotは新しいバージョンが出ると、コミットハッシュとコメントのバージョン番号を両方更新したPRを自動で作成してくれます。レビューしてマージするだけなので、ハッシュ固定でも運用負荷はほとんど変わりません。

GitHub Actionsのセキュリティを強化する関連記事

コミットハッシュの固定はサプライチェーン攻撃対策の第一歩です。GitHub運用のセキュリティ全般もあわせて強化しましょう。

GitHub・セキュリティ

CI/CD・インフラ

まとめ:タグは「ラベル」、ハッシュは「指紋」

本記事のポイントを整理します。

  • @v4のタグ指定は書き換え可能。攻撃者がタグを悪意あるコミットに貼り替えると、あなたのCIで攻撃コードが動く
  • tj-actions事件(CVE-2025-30066)で実際にこの手法が悪用され、23,000以上のリポジトリが影響を受けた
  • コミットハッシュで固定すれば、タグが書き換えられても影響を受けない
  • コメントにバージョンを明記# v4.2.2)して可読性を確保
  • Dependabotで自動更新すれば、ハッシュ固定でも運用負荷はほぼゼロ

タグは「ラベル」です。貼り替えられます。コミットハッシュは「指紋」です。偽造できません。この違いを理解するだけで、CI/CDの安全性は一段上がります。今日のうちに自分のワークフローを開いて、@v4を見つけたらハッシュに置き換えてみてください。5分でできる、最もコスパの高いセキュリティ対策です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次