How to Block Fork Pull Requests From Reading Secrets in GitHub Actions
On the pull_request event, fork PRs get no secrets and a read-only token, which is exactly the safe default to keep.
Use the pull_request event (not pull_request_target) for fork CI; GitHub already withholds secrets and gives a read-only token. If you need secrets, gate the secret-using job behind same-repo or approval checks.
Steps
- Run untrusted PR validation on the
pull_requestevent. - Do not switch to
pull_request_targetand then check out the PR head with secrets. - Gate any secret-using job with
if: github.event.pull_request.head.repo.full_name == github.repository. - Use an Environment with required reviewers for jobs that must touch secrets.
Workflow
.github/workflows/ci.yml
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test # no secrets exposed to forks
deploy-preview:
needs: build
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- run: ./deploy-preview.sh
env:
TOKEN: ${{ secrets.PREVIEW_TOKEN }}Gotchas
pull_request_targetruns in the base repo context WITH secrets; checking out PR code there is the classic exfiltration risk.- Repo settings can also require approval to run workflows on PRs from first-time contributors.
Related guides
How to Stop Secrets Leaking Into Logs in GitHub ActionsPrevent GitHub Actions from printing secrets to logs by masking dynamic values, avoiding set -x with secret a…
How to Audit Which Workflows Can Read a Secret in GitHub ActionsAudit secret usage across GitHub Actions by listing secrets with the gh CLI, grepping workflows for reference…