pull_request_targetは、GitHub Actionsでプルリクエストを起点にワークフローを動かすイベントの一つです。pull_requestと名前は似ていますが、フォークから届いたPRでもベース側のシークレットと書き込みできるトークンが付く点が決定的な違いです。GitHubはこの危うさを理由に、2026年12月2日からパブリックリポジトリでpull_request_targetを既定でブロックします。この記事では、pull_requestとの違い、事故につながる書き方、12月2日までの日程と許可の設定、pull_requestとworkflow_runへ移すYAMLを、11月4日時点の一次情報で整理します。
まとめ:12月2日までに使い道を洗い出し、移すか許可するかを決める
pull_request_targetは、フォークのPRにラベルやコメントを付けるためのイベントです。PRのコードをビルドしたりテストしたりする用途には向きません。ここを取り違えると、外部の人が書いたコードがシークレット付きで動きます。
パブリックリポジトリを持つ組織は、11月9日の最初のブラウンアウトまでに、Policy insightsでブロックされるワークフローを確かめてください。シークレットが要らないものはpull_requestへ移し、ラベル付けのようにPRのコードを動かさないものだけを、イベントポリシーで個別に許可します。プライベートとinternalのリポジトリは対象外です。CIの棚卸しと書き換えを社内で回しきれない場合は、DevOps・CI/CD導入支援でワークフローの見直しを受け付けています。
pull_request_targetの仕組み:既定ブランチで走りシークレットが付く理由
最初に、pull_requestと何が違うのかを確定させます。トリガー全般の選び方はGitHub Actionsのトリガー(on)|イベント選定とbranches・pathsフィルタの設計にまとめており、ここではこのイベントだけを掘り下げます。
pull_requestとの違いを権限・シークレット・取得元の5項目で比べた表
GitHub DocsのEvents that trigger workflowsとSecurely using pull_request_targetから、フォークのPRで起きる違いを並べます。
| 項目 | pull_request | pull_request_target |
|---|---|---|
| GITHUB_TOKEN | 読み取り専用 | ベース側の権限 |
| シークレット | 渡されない | 渡される |
| ワークフロー定義 | PRのマージコミット | 既定ブランチ |
| checkoutの既定 | PRのマージコミット | 既定ブランチの最新 |
| キャッシュ | PRのスコープ | 既定ブランチを読むだけ |
要するに、pull_request_targetは「PRの持ち主ではなく、リポジトリの持ち主として動く」イベントです。既定ではPRのコードを取りに行かないので、それだけなら安全に動きます。危険が生まれるのは、書き手が自分でPRのコードを取り出して実行したときです。
2025年12月8日以降はワークフローとGITHUB_REFが既定ブランチに固定
以前は、PRのベースに指定したブランチにあるワークフロー定義が使われていました。古いブランチに脆弱な定義が残っていると、そのブランチ宛てのPRで狙えたのです。GitHubの2025年11月7日の告知により、12月8日からはベースに関係なく既定ブランチの定義が使われ、GITHUB_REFも既定ブランチを指すようになりました。
同じ変更で、Environmentsのブランチ保護ルールも既定ブランチに対して評価されるようになりました。ブランチ名のパターンで環境を絞っていた構成は、一致しなくなっていないかを確かめておきます。
本来の用途はフォークのPRへのラベル付けとコメントの書き込み
このイベントが用意された理由は、フォークのPRでは読み取り専用のトークンしか得られず、ラベルもコメントも付けられないことにあります。代表例がactions/labelerで、READMEの使用例はpull_request_targetを使っています。
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v6
この定義はPRのコードを取り出しません。変更されたファイルのパスを見て、既定ブランチにある設定ファイルの規則でラベルを付けるだけです。権限もpull-requestsの書き込みに絞っています。pull_request_targetを安全に使える形は、この型に近いものだけだと考えてください。
pwn requestの仕組み:PRのコードをチェックアウトして動かす書き方の危険
pull_request_targetで起きる事故には、pwn requestという呼び名があります。GitHub Security Labの解説が2021年に名付けた型で、GitHub Docsも複数のサプライチェーン侵害の原因だと書いています。
head.shaを指定してmake testを走らせる典型的な脆弱パターン
Docsは、危険な例として次の定義を挙げています。コメントにあるとおり、説明のための例で、使ってはいけません。
# INSECURE. Provided as an example only.
on:
pull_request_target:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Test
run: make test
checkoutだけではコードは動きません。問題は次のmake testで、攻撃者はPRのMakefileを書き換えておけば、ベース側のシークレットとトークンが載ったランナー上で好きなコマンドを実行できます。npm installやビルド設定、テストの設定ファイルも同じ経路になります。
actions/checkout v7と7月20日のバックポートで拒否される取得の範囲
GitHubは2026年6月18日にactions/checkout v7を一般提供とし、pull_request_targetと、PR起点のworkflow_runで、フォークのPRのコードを取りに行く指定を既定で拒否するようにしました。refにPRのheadやmergeを指す値を書いた場合や、repositoryにフォークを指定した場合が対象です。
actions/checkoutのリリース一覧では、同じ拒否がv6.1.0、v5.1.0、v4.4.0、v3.7.0にも入っています。changelogによれば適用日は7月20日で、@v4のようにメジャー版のタグで参照していれば自動で反映されます。コミットSHAやパッチ版で固定しているワークフローには届かないので、SHA Pinningとは?GitHub ActionsをコミットSHAで固定する方法の手順で固定先を上げてください。拒否を外す入力はallow-unsafe-pr-checkoutで、既定値はfalseです。
git fetch・gh pr checkoutと成果物実行が拒否対象外になる条件
checkoutの拒否は、checkoutの入力だけを見ています。runの中でgit fetchやgh pr checkoutを使ってPRのコードを取る書き方、workflow_runで受け取った成果物を実行する書き方は止まりません。issue_commentを起点にPRのコードを動かす構成も同じです。
見落とされやすいのが、PRのタイトルや本文をrunの中へ直接埋め込む書き方です。値がそのままシェルの構文として解釈されるので、コードを取り出さなくてもコマンドを差し込まれます。PR由来の文字列は環境変数として渡し、シェルの中では変数として参照してください。
12月2日の既定ブロック:対象リポジトリとブラウンアウトの日程
ここからが今回の変更です。GitHubの11月2日の告知によれば、パブリックリポジトリでは、適用されるイベントポリシーで明示的に許可しない限り、pull_request_targetのワークフローが動かなくなります。
パブリックだけが対象でprivate・internalとGHESは対象外の範囲
対象は、GitHub Free、GitHub Team、GitHub Enterprise Cloudのパブリックリポジトリです。プライベートとinternalのリポジトリは影響を受けません。自社のサーバーで動かすGitHub Enterprise Serverも、告知で対象外と明記されています。
恒久適用は当初11月2日の予定でしたが、12月2日に延びました。それまでの期間は評価モードで動き、ワークフローは警告付きで実行されます。すでにpull_request_targetを扱うイベントポリシーを設定しているリポジトリでは、既定ポリシーはその設定を置き換えません。
11月9日と11月16日の2時間だけ実行が失敗するブラウンアウト
恒久適用の前に、2回だけ既定ポリシーを一時的に効かせる時間帯が設けられています。この間にブロックされた実行は、エラーの注釈付きで失敗として記録されます。
| 日付 | UTC | 日本時間 | 動き |
|---|---|---|---|
| 2026年11月9日 | 16:00〜18:00 | 11月10日 1:00〜3:00 | ブロックして失敗 |
| 2026年11月16日 | 16:00〜18:00 | 11月17日 1:00〜3:00 | ブロックして失敗 |
| 上記以外〜12月1日 | 終日 | 終日 | 警告付きで実行 |
| 2026年12月2日〜 | 終日 | 終日 | 許可が無ければブロック |
日本時間では深夜の2時間です。海外のコントリビューターが多いOSSでは、この時間帯に開かれたPRでラベラーやコメント係が止まります。夜間に走る仕組みでなければ気づかないまま12月2日を迎えるので、ブラウンアウトの結果を当てにせず、先に洗い出しを済ませます。
Policy insightsとgrepでブロック対象のワークフローを洗い出す手順
止まる実行は、Actionsのポリシー画面の下にあるPolicy insightsで確かめられます。評価モードのポリシーでは、適用されていればブロックされていた実行が、ここでの表示対象です。あわせて、手元のリポジトリでは定義そのものを確かめます。
# 1. 特権のあるトリガーを使うワークフロー
grep -rnE "pull_request_target|workflow_run|issue_comment" .github/workflows/
# 2. PRのコードを取り出す書き方と、拒否を外す指定
grep -rnE "head\.sha|head\.ref|refs/pull/|gh pr checkout|git fetch|allow-unsafe-pr-checkout" .github/workflows/
# 3. 組織内のパブリックリポジトリの一覧(GitHub CLI)
gh repo list your-org --visibility public --limit 200 --json nameWithOwner -q ".[].nameWithOwner"
1で出たファイルのうち、2にも当たるものが最優先です。pull_request_targetでPRのコードを取り出していれば、ブロック以前に今すぐ直すべき箇所です。1にだけ当たるものは、次の章の分け方で移すか許可するかを決めます。
移行と許可の手順:pull_requestとworkflow_runへ移す書き換え例
Securely using pull_request_targetは、影響を受けるワークフローごとに、より安全なイベントへ移す、明示的に許可する、ブロックされるに任せる、の3つから選ぶよう求めています。順に見ていきます。
シークレットが要らないテストとビルドはpull_requestへ書き換え
テストやlintをpull_request_targetで動かしているなら、多くはシークレットを使っていません。その場合は、onをpull_requestに変え、PRのコードを指していたrefの指定を消すだけで済みます。pull_requestはフォークのPRでも、読み取り専用のトークンとシークレット無しで安全に動きます。
あわせてpermissionsでcontents: readに絞っておくと、後から誰かがトリガーを戻したときの被害も小さくなります。権限の絞り方はGitHub Actionsのpermissions|GITHUB_TOKENの既定権限と最小権限の設計で扱っています。
テスト結果をPRへ書き込む処理はworkflow_runで2段に分ける構成
テストの結果をPRにコメントしたい、という要望がpull_request_targetを使う理由になりがちです。この場合は、PRのコードを動かす段と、書き込む段を分けます。前段はpull_requestで権限なしに動かし、結果だけを成果物として残します。
# .github/workflows/pr-test.yml(PRのコードを権限なしで動かす段)
name: pr-test
on:
pull_request:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm ci
- run: npx jest --json --outputFile=result.json
- run: echo "${{ github.event.number }}" > pr_number.txt
- uses: actions/upload-artifact@v4
with:
name: pr-result
path: |
result.json
pr_number.txt
後段はworkflow_runで起動し、書き込みの権限を持つ構成です。成果物は攻撃者が中身を決められるデータとして扱い、実行せずに値だけを読みます。PR番号も数字以外を捨ててから使います。
# .github/workflows/pr-comment.yml(結果だけを読んで書き込む段)
name: pr-comment
on:
workflow_run:
workflows: ["pr-test"]
types: [completed]
permissions:
actions: read
pull-requests: write
jobs:
comment:
if: github.event.workflow_run.event == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: pr-result
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
- name: 数字だけを取り出してコメントする
env:
GH_TOKEN: ${{ github.token }}
run: |
PR=$(tr -cd '0-9' < pr_number.txt)
PASSED=$(jq -r '.numPassedTests' result.json | tr -cd '0-9')
gh pr comment "$PR" --repo "$GITHUB_REPOSITORY" --body "テスト成功: ${PASSED}件"
後段ではcheckoutもnpm ciもしていない点が肝心です。Docsも、workflow_runで受け取る成果物は信頼できないデータとして扱うよう書いています。ここでcheckoutを足してPRのコードを動かすと、pull_request_targetの事故と同じ形に戻ります。
許可が要るワークフローをイベントポリシーでファイルごとに通す設定
ラベラーのように、PRのコードを動かさずにフォークのPRへ書き込む処理は、移しようがありません。これらは許可します。Governing execution of GitHub Actions workflowsによれば、設定はリポジトリか組織のSettingsにあるActionsのPolicies、エンタープライズではPoliciesタブから行います。
Restrict eventsでpull_request_targetを許可し、適用先をワークフローのパスで絞ります。リポジトリ全体で許可すると、後から足された別のワークフローまで通ってしまうので、許可は.github/workflows/labeler.ymlのようにファイル単位にします。ポリシーの状態に「Evaluate」を選んで事前に影響を見られるのは、GitHub Enterprise Cloudだけです。
受託開発での判断:許可するもの・移すもの・止めてよいものの線引き
ここまでの事実を踏まえ、どのワークフローを残すかを言い切ります。基準はリポジトリの公開範囲と、PRのコードを動かすかどうかの2点です。
プライベートの業務システムでも既定ブロック対象外を理由に放置しない
受託開発の業務システムは、ほとんどがプライベートリポジトリです。12月2日の変更の対象外なので、何もしなくても止まりません。ただ、止まらないことと安全なことは別です。社内のメンバーしかPRを出せないなら、pull_request_targetを使う理由そのものがありません。
プライベートで使われているpull_request_targetは、pull_requestへ移します。将来リポジトリを公開したときや、協力会社にフォークでPRを出してもらう運用に変えたときに、そのまま事故の入口になるからです。シークレットの置き場所と漏れる経路はGitHub ActionsのSecrets管理|置き場所の選定と漏えい経路・OIDC移行の判断で整理しています。
OSSで許可してよいのはPRのコードを一切動かさない書き込み処理だけ
パブリックのOSSでpull_request_targetを許可してよいのは、ラベル付け、初回コントリビューターへの挨拶、PRのサイズ判定のように、PRのコードを取り出さない処理に限ります。checkoutにallow-unsafe-pr-checkoutを書いた定義は、許可の対象から外します。拒否を外してまでPRのコードを取る必要があるなら、それは前の章の2段構成で組み直すべき処理です。
キャッシュも、汚染の経路として注意が必要です。Docsによれば、pull_request_targetのワークフローは既定ブランチのキャッシュを読むだけで、保存は警告を出して失敗します。保存したいからといって書き込みを許す設定を足すと、キャッシュの汚染が成立するため危険です。保存はpushなど信頼できるトリガーの側で行い、key設計はGitHub Actionsのキャッシュ|actions/cacheのkey設計と復元されない原因の切り分けに沿って決めます。
使われていないワークフローはブロックに任せて削除まで済ませる判断
洗い出しで、誰が足したか分からない、何年も成功していないpull_request_targetの定義が出てくることがあります。こうしたものに許可は要りません。12月2日のブロックに任せたうえで、定義ファイル自体を消します。残しておくと、後から誰かが許可したときに古い書き方のまま動き出します。
パブリックリポジトリが数十本あり、定義の読み解きと書き換えを12月2日までに終えられないなら、外部の手を借りる時期です。棚卸しから移行後の動作確認までは、DevOps・CI/CD導入支援で請け負っています。
pull_request_targetの既定ブロックと移行でよくある質問と回答
12月2日の変更と、pull_request_targetの使い方で出てきやすい疑問に、11月4日時点の一次情報の範囲で答えます。
pull_requestとpull_request_targetはどちらを使えばよいですか?
原則はpull_requestです。pull_request_targetは、フォークのPRに対してシークレットや書き込みの権限が必要で、かつPRのコードを一切動かさない処理に限って選びます。テスト、lint、ビルドのようにPRのコードを動かす処理は、どれもpull_requestで動かす処理です。結果をPRに書き込みたいときは、workflow_runとの2段構成にします。
プライベートリポジトリでも12月2日に止まりますか?
止まりません。GitHubの告知とDocsは、プライベートとinternalのリポジトリは対象外だと明記しています。ただし、リポジトリを後から公開すると、その時点からは既定ポリシーの対象です。公開を予定しているリポジトリは、公開前にpull_request_targetの定義を整理しておくと、公開した日にラベラーが止まる事態を避けられます。
actions/checkoutをSHAで固定している場合はどうなりますか?
フォークのPRのコードを拒否する機能は、v7とバックポートしたv6.1.0、v5.1.0、v4.4.0、v3.7.0に入っています。それより前のコミットSHAで固定していると、拒否は効きません。固定先のSHAが上記の版以降かを確かめ、古ければDependabotなどで上げてください。12月2日の既定ブロックとは別の仕組みなので、両方を確かめます。
ブラウンアウトで失敗した実行は再実行すれば通りますか?
ブラウンアウトの2時間が過ぎれば評価モードに戻るので、再実行すれば警告付きで動きます。ただし、それで済ませると12月2日に同じ失敗が恒久的に起きます。失敗したワークフローは、ブロックされる対象が実際にあったという知らせです。移すか許可するかを、その場で決めてください。
allow-unsafe-pr-checkoutを付ければ従来どおり動きますか?
checkoutの拒否は外れますが、12月2日の既定ブロックはイベントポリシーの話なので、別途イベントポリシーでの許可が必要です。actions/checkoutのaction.ymlは、この入力をリスクを確認したうえでだけtrueにするよう書いています。名前はレビューで見つけやすいように付けられており、付けた定義はPRのコードを動かしていないかを必ず確かめる対象になります。
関連記事
- GitHub Actionsとは?できること・使い方と最初のワークフロー、料金と上限【2026年10月】:GitHub Actionsの全体像と、ワークフローの基本の書き方です。
- actionlintとは?GitHub Actionsワークフローの静的解析ツールの使い方・インストール・設定:runへの直接埋め込みなど、危険な書き方を機械で見つける方法です。
- GitHub ActionsのEnvironments|承認ゲートと環境別シークレットの設計:シークレットを使うジョブの前に承認を挟む設計です。
- Reusable Workflows(GitHub Actions)の使い方:workflow_callの定義と呼び出し、secrets・outputs・上限:書き換えたワークフローを複数のリポジトリで共通化する方法です。