actions/checkout v7のpull_request_target保護についてまとめる

Tips

はじめに

GitHub Blogで、actions/checkout v7に関する重要な変更が公開されていました。 内容は、pull_request_target を使う GitHub Actions ワークフローで、fork から来た Pull Request のコードを不用意に checkout しにくくする変更です。

筆者もGitHub Actionsでワークフローを作成しているため、変更点を見ると、まず「既存のワークフローが突然失敗しないか」と「セキュリティ上の危ない書き方をしていないか」を確認します。 今回の変更はまさにその両方に関係します。 actions/checkout@v4 のようなメジャーバージョン固定でも、2026年7月16日以降に挙動が変わる可能性があるためです。

今回は、GitHub Blogの「Safer pull_request_target defaults for GitHub Actions checkout」の内容をもとに、概要、注意点、対応しておくべきことを整理します。

先に結論

今回の変更で一番大事なのは、pull_request_target 上で fork PR のコードを checkout して実行するパターンが、actions/checkout 側で既定ブロックされるようになる点です。

pull_request_target は、base リポジトリ側の権限で動きます。 そのため、GITHUB_TOKEN、Secrets、default branch 側のキャッシュなど、通常の fork PR には渡したくない権限にアクセスできます。 この状態で、未レビューの fork PR のコードを checkout して npm testmake test などを実行すると、攻撃者が用意したコードを高い権限で実行してしまう可能性があります。

GitHub Blogでは、このようなパターンを pwn request と呼び、複数のサプライチェーンインシデントの原因になってきたと説明しています。 今回の actions/checkout v7は、この典型的な危険パターンを既定で失敗させる変更です。

何が変わるのか

2026年6月18日に actions/checkout v7 が一般提供されました。 このバージョンでは、pull_request_target で起動したワークフローが fork PR のコードを checkout しようとすると、危険なパターンとして拒否されます。

対象になるのは、主に次のような指定です。

指定 何が危ないか
repository: ${{ github.event.pull_request.head.repo.full_name }} fork 側のリポジトリを直接 checkout する
ref: refs/pull/${{ github.event.pull_request.number }}/merge PR の merge ref を checkout する
ref: ${{ github.event.pull_request.head.sha }} PR head のコミットを checkout する

また、workflow_run でも、元のイベントが pull_request 系である場合に fork PR のコードを actions/checkout で取得しようとすると保護対象になります。 ただし、fork PR 由来の artifact を後続ワークフローで実行するような構成は、今回の actions/checkout の保護範囲外でも同種のリスクがあるため、別途点検が必要です。

重要なのは、この変更が actions/checkout@v7 だけの話で終わらない点です。 GitHub Blogによると、2026年7月16日に、現在サポートされている主要バージョンにもこの強制がバックポートされる予定です。 そのため、actions/checkout@v4 のように floating major tag を使っている(メジャーバージョンまで指定している)ワークフローは、自動的にこの変更を受け取ります。

一方で、特定の SHA、minor、patch バージョンに固定している場合は、バックポートの影響を直接は受けません。 ただし、その場合も安全になるわけではありません。 危険な構成が残ったままになりやすいため、Dependabot や通常の更新手順で明示的に見直す必要があります。

pull_request_target が危なくなる理由

pull_request_target 自体が常に危険というわけではありません。 本来は、fork から来た Pull Request に対して、ラベル付け、コメント、メタ情報の確認などを安全に行うために用意されています。

通常の pull_request イベントでは、fork PR からの変更を扱う際、Secrets が渡されなかったり、GITHUB_TOKEN の権限が制限されたりします。 これは未レビューのコードを実行する前提では安全側となる制限です。

一方で、pull_request_target は base リポジトリの default branch にあるワークフローを実行します。 ワークフロー定義自体は信頼済みの default branch から来るため、Secrets や書き込み権限を使える設計になっています。 ここまでは安全です。

問題は、その後に fork PR のコードを checkout して実行する場合です。 たとえば、次のような構成です。

on:
  pull_request_target:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}

      - run: npm ci
      - run: npm test

この例では、ワークフロー定義は base 側のものですが、checkout されるコードは fork PR 側です。 その状態で npm cinpm test を実行すると、package.json、依存関係、テストスクリプトなどを通じて、PR 作成者が用意した処理が動く可能性があります。 Secrets や書き込み可能な GITHUB_TOKEN を持った状態でこれを実行するのが、pwn request の典型的な形です。

checkout しただけでは、まだ任意コード実行ではありません。 しかし、実際のCIでは checkout の直後に build、test、lint、coverage 生成などを行うことが多いです。 そのため、checkout の指定は小さく見えても、後続ステップと組み合わさると大きなリスクになります。

何が変わらないのか

今回の変更は強力ですが、すべての危険なワークフローを自動で直してくれるものではありません。 actions/checkout が検知できる範囲に限られます。

たとえば、次のようなケースは別途注意が必要です。

ケース 注意点
run ブロック内で git fetch する actions/checkout の保護を通らない
gh pr checkout を使う PR head を手動取得して実行する可能性がある
issue_comment/test コメントを契機にする 今回の保護対象外のイベントでも同じリスクが作れる
第三者リポジトリを checkout する fork PR 以外の未信頼コードは別問題として残る
workflow_run で成果物を実行する fork PR 由来の artifact を信頼してしまう可能性がある

特に見落としやすいのは、actions/checkout を使わずに gitgh コマンドで PR のコードを取得しているケースです。 今回の変更は、actions/checkout の入力に対する保護です。 ワークフロー内の任意のシェルコマンドまで、すべて安全化してくれるわけではありません。

また、同一リポジトリ内の Pull Request は今回の影響を受けません。 pull_request イベントそのものの挙動も変わりません。 影響範囲は、主に fork PR と、権限の高いイベントで未信頼コードを扱う構成です。

影響を受けやすいワークフロー

今回の変更で壊れる可能性があるのは、もともと危険な形に近いワークフローです。 ただし、実務上は「理由があってそうしている」場合もあります。

たとえば、private package registry にアクセスしないとテストできないリポジトリでは、fork PR のコードをテストしながら Secrets も使いたくなることがあります。 coverage report を外部サービスへ送る場合も同じです。 このような背景から、pull_request_target と PR head checkout を組み合わせたくなります。

しかし、この構成では未レビューのコードと高い権限が同じジョブに同居します。 設計としてはかなり慎重に扱う必要があります。

筆者が点検するなら、まず次のような条件で検索します。

rg "pull_request_target|workflow_run|github.event.pull_request.head|refs/pull|head.repo.full_name" .github/workflows

この検索で見つかったワークフローは、次の観点で読みます。

観点 確認すること
イベント pull_request_targetworkflow_run を使う必要が本当にあるか
checkout fork PR の head.shahead.repo.full_name を指定していないか
後続ステップ checkout したコードを build、test、install、script 実行していないか
Secrets ジョブ内で repository secrets や organization secrets を使っていないか
token 権限 permissions が最小権限になっているか
runner self-hosted runner で内部ネットワークへ到達できないか

pull_request_target があるだけで即修正ではありません。 ただし、fork PR のコードを checkout して、そのまま実行している場合は優先度を上げて見直したほうがよいです。

対応しておくべきこと

まず、Secrets が不要なCIは pull_request に寄せるのが基本です。 fork PR のコードを build や test するだけなら、pull_request_target ではなく pull_request で十分な場合が多いです。

on:
  pull_request:

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: npm ci
      - run: npm test

この形では、PR のコードをテストできます。 一方で、fork PR に対して Secrets を渡す前提ではありません。 未信頼コードを実行する場所と、権限の高い処理を行う場所を分けられます。

次に、pull_request_target を使う必要があるワークフローでは、PR のコードを checkout しない構成に寄せます。 ラベル付けやコメントだけなら、ソースコードを checkout しなくても API で処理できます。

on:
  pull_request_target:

permissions:
  contents: read
  pull-requests: write

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - name: Add comment
        run: gh pr comment "$PR_NUMBER" --body "確認します。"
        env:
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ github.event.pull_request.number }}

この例では checkout をしていません。 ワークフローの目的がコメントやラベル操作であれば、PR のコードを取得しないほうが構成が単純で安全です。

どうしても fork PR のコードを扱う必要がある場合は、権限分離を検討します。 たとえば、pull_request で未信頼コードをテストし、その結果を artifact や check result として扱います。 その後、権限の高いワークフローでは、artifact を「実行可能なコード」ではなく「データ」として読むようにします。

ここで大事なのは、artifact も信頼しすぎないことです。 fork PR 由来の artifact には、攻撃者が自由に内容を書けます。 JSON やテキストとして検証しながら読むのはまだ扱いやすいですが、script として実行したり、設定ファイルとして読み込ませたりすると、結局同じリスクに戻ります。

opt-out は最後の手段にする

actions/checkout v7 では、allow-unsafe-pr-checkout という入力を指定すると、この保護を明示的に外せます。 名前のとおり、コードレビューで見つけやすいように危険性が分かる名前になっています。

- uses: actions/checkout@v7
  with:
    ref: ${{ github.event.pull_request.head.sha }}
    allow-unsafe-pr-checkout: true

この指定は、単に「今まで動いていたワークフローを動かし続けるため」の逃げ道として使うべきではありません。 GitHub のガイドでは、pull_request_target が本当に必要か、checkout したコードが実行されないか、Secrets や token 権限を最小化できているかを確認するように説明されています。

特に、checkout 後に次のような処理がある場合は、opt-out で済ませるのは危険です。

  • npm installnpm cinpm test
  • makemake test
  • pip install -r requirements.txt
  • bundle install
  • PR に含まれる script や設定ファイルを読み込むツール
  • fork PR 由来の artifact を実行する処理

これらは、見た目には普通のCI手順です。 しかし、未信頼コードを実行する入口にもなります。 allow-unsafe-pr-checkout: true を付ける場合は、なぜ必要なのか、どの権限を持った状態で何を実行するのかを、ワークフロー内のコメントやレビュー記録に残したほうがよいです。

2026年7月16日までに確認したいチェックリスト

今回の変更は、2026年7月1日時点では actions/checkout@v7 を使う場合に直接関係します。 ただし、2026年7月16日にサポート中の主要バージョンへバックポート予定とされています。 そのため、actions/checkout@v4 のような指定でも、早めに点検したほうがよいです。

最低限、次の項目は確認しておくと安心です。

チェック 見るポイント
pull_request_target の有無 本当に privileged context が必要か
workflow_run の用途 PR 由来の artifact やコードを実行していないか
actions/checkoutref head.sharefs/pull/.../merge を指定していないか
actions/checkoutrepository head.repo.full_name を指定していないか
run 内の取得処理 git fetchgh pr checkout で PR code を取得していないか
permissions contents: read など最小権限に寄せられるか
Secrets fork PR 由来のコードと同じジョブに置いていないか
action の更新 actions/checkout@v7 へ上げる計画があるか

個人的には、まず「pull_request_target で checkout しているか」を見るのが一番効率的だと思います。 次に、checkout した後に実行しているコマンドを見ます。 この2つを見るだけでも、危険な形の大半は見つけやすくなります。

まとめ

actions/checkout v7 の変更は、pull_request_target の危険な使い方を防ぐ方向のアップデートです。 fork PR のコードを、base リポジトリの Secrets や書き込み token を持つワークフローで checkout して実行する構成は、今後より明確に止められるようになります。

注意点は、今回の保護が actions/checkout の典型パターンに限られることです。 git fetchgh pr checkoutissue_comment、未信頼 artifact の実行など、別経路で同じリスクを作ることはできます。 そのため、単に actions/checkout@v7 へ上げるだけでなく、未信頼コードと Secrets を同じ場所に置かない設計になっているかを確認する必要があります。

今回の作業で改めて感じたのは、CIのセキュリティは「どのイベントで動くか」と「どのコードを実行するか」の組み合わせで決まるということです。 pull_request_target は便利ですが、便利さの理由は強い権限を持てることでもあります。 2026年7月16日のバックポート前に、該当するワークフローだけでも一度棚卸ししておくのがよさそうです。

参考情報:

コメント

タイトルとURLをコピーしました