
GitHub Actionsの「@v7」は信用できるのか――GAになったactions.lockで依存を固定する
こんにちは。ディアシステム開発二部の箕浦です。
毎日、Qiita・Zenn・Xから技術トレンドを集めて、その中から1つテーマを選んで掘り下げています。今日のテーマは 「GitHub Actionsの依存をどう固定するか(actions.lock)」 です。
なぜ今日このテーマなのか
今日のトレンドを横断すると、「AIで速く作る」話題が多い一方で、「作ったものを安全に回す」話題もはっきり目立っていました。
- Zenn:「GitHub Actions で checkout@v7 のようなバージョン指定を書くのはやめよう! 時代は actions.lock!」(Progate)が、本日のデイリー上位に入っていました。ほかに「今後のセキュリティの考え方」も上位です。
- Qiita:「【Curl】致命傷じゃないセキュリティ脆弱性はフルオープンにするわ」や、PHP・Node・Chrome・Goなどの脆弱性が同じ週に重なったという体験記が人気記事に並んでいました。
- X:同じZennの記事を紹介する投稿が、検索結果の上位に出ていました。
さらに、記事の背景にあるGitHub公式の発表は、2026年10月28日にワークフローのlockfileが一般提供(GA)になったというものです。つまり「書き方の工夫」だった対策が、「公式の機能」になったタイミングです。社内でもGitHub Actionsを使っている現場は多いので、今日はここを掘り下げます。
1. 問題:@v7 は「その時点で指しているコミット」を実行する
GitHub Actionsで uses: actions/checkout@v7 と書くと、実行のたびに、そのタグがその時点で指しているコミットが取得されます。タグは付け替えられる(強制pushで別のコミットを指させられる)ので、レビューしたコードと、実際に動くコードが一致する保証がありません。GitHubの公式ドキュメントも、アクションが1つ侵害されるとリポジトリのシークレットにアクセスされ、GITHUB_TOKEN で書き込みまでされうる、と説明しています。
これは理屈だけの話ではありません。2026年3月に起きたTrivyの事件が、典型的な例です。
実例:Trivyのサプライチェーン侵害(2026年3月)
TrivyのGitHubセキュリティアドバイザリ(GHSA-69fq-xp46-6x23)によると、3つの成果物が侵害されました。要点は次のとおりです。
trivy-action:77個あるバージョンタグのうち76個が、悪意あるコミットへ強制pushされました。entrypoint.shに情報窃取のコードが入り、本来のスキャンより前に実行されました。ランナーのメモリからシークレットを抜き出し、SSH鍵やクラウドの認証情報などを探して、暗号化して外部へ送る動きだったと説明されています。影響の期間は約12時間です。setup-trivy:既存タグがすべて差し替えられました(約4時間)。- Trivy本体のバイナリ:v0.69.4が悪意ある内容で公開されました(約3時間)。
ここで私が一番学びになると感じたのは、**「SHAで固定していても、守れない場合があった」**という点です。アドバイザリでは、2025年4月9日より前のコミットでSHA固定していた場合も、setup-trivy の侵害の影響を受けうるとされています。trivy-action の内部が、別のアクション(setup-trivy)をタグで参照していたためです。自分のワークフローで固定しても、依存先の依存先までは固定されていませんでした。
一方で、影響を受けなかった条件も書かれています。タグ 0.35.0(GitHubのImmutable Releasesで保護)や、安全なコミットに固定していた場合です。
2. 対策の整理:タグ → SHA固定 → lockfile
対策を段階で並べると、こうなります。
| 方法 | 何が守られるか | 弱点 |
|---|---|---|
タグ指定(@v7) | 何も守られない(動くタグに追従) | タグの付け替えで中身が変わる |
| タグ指定+Immutable Releases | リリース側が機能を使っていれば、タグの付け替えを防げる | 使うかどうかは提供元しだい。記事執筆時点で actions/checkout は未使用と書かれていた |
| 完全なコミットSHAで固定 | 自分の uses: の参照先は固定される | 依存先の依存先は固定できない。可読性が落ちる。Dependabotのアラートが出なくなる(後述) |
| actions.lock | 依存先の依存先(推移的依存)まで、コミットを記録して固定 | 導入と更新の運用が必要(後述) |
GitHub公式のドキュメントには、現時点では「アクションを不変のリリースとして使う唯一の方法は、完全なコミットSHAに固定すること」という記述(セキュアな利用のページ)も残っています。一方、lockfileのページには、lockfileを採用したリポジトリではワークフロー内のSHA固定は「もはや不要」と書かれています。公式ドキュメント間で、更新の進み具合に差があることがわかります。
3. actions.lockの仕組み
GitHub公式のドキュメントと、拡張機能 gh-actions-lock のREADMEから、仕組みをまとめます。
- ファイルは
.github/workflows/actions.lockです。GitHub CLIの拡張gh actions-lockで生成し、手では編集しません。 - ワークフローには
@v7.0.1のように読みやすいバージョンを書き、正確なコミットはlockfile側が記録します。 - 記録されるのは、
ref(タグなど)、commit(実際のコミット)、owner_id/repo_id(リポジトリの数値ID)です。リポジトリIDまで記録するので、「名前は同じでも別のリポジトリにすり替わった」ことを検出できます。 - アクションが内部で使う別のアクション(推移的依存)も、同じように記録されます。
- 導入はワークフロー単位です。導入(onboard)したワークフローは、すべての依存がlockfileに載っている必要があり、実行時は記録されたコミットが使われます。許可アクションのポリシーも、ロックされたコミットに対して評価されます。
- GAで、DependabotのバージョンアップPRにlockfileの更新が同梱されるようになりました。管理者向けに、lockfileを必須にする「Require lockfile」ポリシーもあります。
導入のコマンドは、gh extension install github/gh-actions-lock で拡張を入れ、リポジトリで gh actions-lock を実行するだけです。更新用に --relock、CI用の検証に --verify、pre-commit向けのオフライン確認に --verify-local があります(正確なオプションは --help が正、とREADMEに書かれています)。
「ロックした=安全」ではない
ここは誤解しやすいので強調します。GitHubの発表も明記しているとおり、lockfileは依存先が安全であることを判定しません。固定されるのは「ロックした時点のコミット」です。ロックする前に中身(と公開されてからの経過)を確認するのは、人間の仕事です。Trivyの事件のように、悪意あるコミットが公開された直後にロックしてしまえば、その悪意あるコミットを固定してしまいます。
4. 導入で気をつけたい落とし穴
公式ドキュメントとREADMEに加え、ClassmethodのGA後の検証記事(著者が自分で試した結果)から、現場で効きそうな点を整理します。検証記事は個人の検証であり、公式の保証ではない点は割り引いて読んでください。
(1) 制限事項(READMEより)
- 別リポジトリから呼ばれる再利用可能ワークフローはロックされません(
jobs.<id>.usesでの呼び出し)。 - ローカルアクション(
./...)は追跡もロックもされません。リモートのアクションを使うローカルアクションは、対処するまでブロッキングエラーになります。 - コンテナイメージはロックされません。
@sha256:のダイジェスト指定がないイメージは警告になります。 - GitHub Enterprise Serverは対象外です。
- 浮動参照(
v4やmain)が、履歴内の古いコミットへ戻る変更は検出されないと書かれています。lockfileの差分レビューか、正確なタグでの固定が必要です。
つまり、「全部が守られる」わけではありません。社内の使い方が、どの制限に当たるかを先に洗い出すのが大切です。
(2) 更新漏れは、PRのチェックに出ないことがある
検証記事では、lockfileを更新し忘れたPRで、導入済みのワークフローが startup_failure になりました。ただし、PRのチェック一覧には現れず、見えたのは --verify を実行するチェックだけだったそうです。CIに --verify を入れておくことが、気づくための前提になります。必須チェックにしないと取りこぼす可能性もありますが、その点は検証されていません。
(3) --verify の固定バージョンに注意
検証では、公式サンプルが指定していた旧バージョンの --verify が、複合アクション内部の参照のズレを見逃し、新しいバージョンでは検出できたと報告されています。サンプルをそのままコピーせず、使うバージョンを確認するのが無難です。
(4) Require lockfileは、一度に強くしない
公式ドキュメントは「運用の仕組みができる前に、Activeモードにしないこと」と警告しています。進め方も示されています。①導入済みのリポジトリだけで、②まずEvaluateモード(GitHub Enterprise限定)で結果を見て、③lockfileが古くならない仕組み(Dependabot、更新用ワークフロー、pre-commitなど)を用意し、④actions.lock をCODEOWNERSに入れてコードオーナーの承認を必須にしてから、⑤Activeにします。検証記事では、Activeでは、アクションを使わないだけのワークフローも未導入なら動かなくなった、とあります。
(5) 副作用:SHAのコメント付き参照が書き換わる
導入すると、@<SHA> # v7.0.1 のような参照が @v7.0.1 に書き換わったそうです。SHA前提のチェックを自前で持っている場合は見直しが必要です。
(6) Dependabotとの関係
公式ドキュメントによると、SHAで固定したアクションには、Dependabot alertsが作成されません(セマンティックバージョンで参照した場合のみ対象)。lockfile方式は、読みやすいバージョン表記が残るので、この点でも運用しやすい可能性があります。ただし、Dependabotは未導入のワークフローを自動で導入はしないので、新しいワークフローは自分で導入する必要があります。
(7) AIが書いたハッシュを信じない
Zennの記事のコメント欄には、LLMに「SHAで固定して」と頼んだら、存在しない(誤った)ハッシュが提案された、という報告がありました。SHAは人間もAIも間違えやすいので、gh actions-lock のようにツールが解決・検証する仕組みに任せるほうが安全、という方向を後押しする話です。
5. ロックだけでは終わらない:公式が挙げる他の対策
サプライチェーン対策は、lockfileだけでは完結しません。GitHub公式の「セキュアな利用」のページが挙げる項目のうち、特に現場で効くものを並べます。
GITHUB_TOKENの既定権限を読み取りのみにする(書き込みはジョブ単位で付ける)。アクションが侵害されたときの被害の上限を決めます。- クラウドへの認証はOIDCを使う。長期間有効なシークレットを置かなければ、盗まれる対象が減ります。
.github/workflowsをCODEOWNERSに指定し、ワークフローの変更に承認を必須にする。pull_request_targetとworkflow_runは原則使わない。使う場合も、信頼できないPRのコードをチェックアウトしない。- セルフホステッドランナーは、公開リポジトリでは避ける。
- CodeQLやOpenSSF Scorecardsなどでワークフロー自体を診断する。Zennの記事のコメントでは、静的チェックツールのzizmorも紹介されていました。
Trivyの事例でも、アドバイザリの推奨に「シークレットのローテーション」と「実行ログの確認」が入っています。固定は予防、ローテーションとログ確認は事後対応という役割分担です。
6. 現場で使えるチェックリスト
社内のリポジトリで、今日から確認できる項目をまとめます。
- 棚卸し:自分たちのワークフローが使っている外部アクションを一覧にする(依存関係グラフでも確認できます)。
@mainや、メジャーだけの@v4が残っていないか見る。 - ロックする前にレビュー:ロックしたい版が、公開から日が浅くないか、リリースノートに不審な点がないか確認する。
gh actions-lockで導入:まず影響の小さいリポジトリ、小さいワークフローから。変更されたワークフローとlockfileを、同じコミットで確認する。- CIに
--verifyを入れる:サンプルのバージョン固定は最新かを確認し、可能なら必須チェックにする。 - Dependabotの
github-actionsを設定:更新PRでlockfileも一緒に更新されることを、1回試して確かめる。 actions.lockをCODEOWNERSに追加:コードオーナーの承認を必須にする。- 制限に該当しないか確認:再利用可能ワークフローの呼び出し、ローカルアクション、コンテナイメージを使っていれば、別の対策(定義元でのlockfile、ダイジェスト指定)を考える。
- 権限の最小化:
GITHUB_TOKENの既定を読み取りのみにし、長期シークレットはOIDCへ。 - 事故前提の準備:侵害の通知が出たとき、「どのワークフローが、どのシークレットで、いつ実行されたか」を追える状態にしておく。
- Require lockfileは最後:上が回り始めてから、Evaluate、Activeの順に進める。
まとめ
@v7のようなタグ指定は、レビューしたコードと実行されるコードが同じである保証がない。Trivyの事例(2026年3月)がそれを示した。- SHA固定は有効だが、依存先の依存先までは固定できない。lockfile(actions.lock)は、その部分までコミットを記録して固定する公式の仕組みで、2026年10月28日にGAになった。
- ただしlockfileは**「安全の判定」ではなく「固定」**。ロック前のレビュー、更新漏れを検出するCI、Require lockfileの段階的な導入が、運用の本体になる。
- 再利用可能ワークフロー、ローカルアクション、コンテナイメージなど、守られない範囲がある。自社の使い方に当てはめて確認する。
- 固定は予防の1つ。権限の最小化、OIDC、シークレットのローテーション、ログの確認と組み合わせて使う。
なお、本記事の検証系の内容(ClassmethodのGA後の運用記事など)は個人の検証に基づくもので、組織ポリシーや別リポジトリの再利用可能ワークフローなど、未検証の範囲が明記されています。実際に導入する際は、小さなリポジトリで試してから広げてください。
明日もトレンドを追いかけます。
