Fork からの PR で GitHub Actions の Secrets が使えない
セキュリティ上、`pull_request` イベントは fork 側のワークフローに secrets を渡さない仕様。
`pull_request_target` への切り替え、信頼境界を切り分けたジョブ設計、Environments での承認ゲートを組み合わせて安全に解決する。
公開:
要約
Fork からの PR で secrets が undefined になるのは 意図された仕様。
悪意ある PR が secret を盗まないように、pull_request イベントでは fork 側ワークフローに secrets を渡さない設計になっている。pull_request_target への切り替え、ジョブ分離、Environment 承認制を組み合わせて安全に対処する。
よくある原因
pull_requestの仕様: fork PR のpull_requestイベントでsecrets.FOOは常に空文字を返す。
これは automatic token authentication で明示された挙動。GITHUB_TOKEN縮小: 同イベントでGITHUB_TOKENも実質 read 相当の権限まで絞られ、コメントや label の付与もできなくなる。- ワークフロー混在: secrets を使うデプロイ処理を fork PR と同じワークフローで動かしており、毎回 fork PR で失敗する。
pull_request_targetの checkout 罠:pull_request_targetは base ブランチで動くため、actions/checkoutを素で書くと PR 側コードを落とせない。
逆に PR 側コードを安易に落として secrets と組み合わせると重大な脆弱性になる。
解決策
1. ジョブを分離する
lint / typecheck など PR 側コードを実行するジョブは pull_request のまま、secrets を使う E2E や preview deploy だけを pull_request_target に切り出す。
on:
pull_request: # PR コードを実行する側(secrets なし)
pull_request_target: # secrets を使う側(PR コードは実行しない)
jobs:
lint:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run lint
preview-deploy:
if: github.event_name == 'pull_request_target'
environment: preview
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: ./scripts/deploy-preview.sh
env:
PREVIEW_TOKEN: ${{ secrets.PREVIEW_TOKEN }}2. PR コードを実行しないジョブ設計にする
Events that trigger workflows の pull_request_target 節のとおり、pull_request_target は base ブランチの状態で動くことが前提。PR 側コードを checkout して secrets と同居させる構成は避ける のが鉄則。
3. Environment で承認ゲート
Settings → Environments で Required reviewers を設定すると、その environment を要求する job は maintainer が手で承認するまで開始されない。
fork PR でも secrets を解決する処理は Environment 越しに通す設計にすれば、人手承認なしには走らない。
4. push トリガーに退避する
on:
push:
branches: [main]リリースやデプロイの本処理は push トリガーに移すと、fork PR から動かす必要が無くなり secrets 問題は根本的に消える。