Many teams know this pattern: a pull request from a fork arrives, and a workflow on pull_request_target immediately checks out the PR code. It is convenient because the job can run tests, post a comment, or prepare a follow-up action with repository access. The catch is that the workflow already runs with the base repository’s GITHUB_TOKEN, secrets, and runner context while the code itself comes from an outside contributor.
On June 18, 2026, GitHub changed actions/checkout v7 so it refuses unsafe fork PR checkouts by default in scenarios such as pull_request_target and workflow_run. That is not a cosmetic update. It forces teams to make the trust boundary explicit instead of relying on a habit that used to work by accident.
Before
This is the risky shape:
name: pr-check
on:
pull_request_target:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: npm test
At first glance it looks harmless: just test the code from the PR. But pull_request_target runs in the base repository context. If the fork changes scripts, workflow inputs, or anything that touches secrets, the blast radius is much larger than a broken test run.
After
The safer answer is to stop mixing privileged access with untrusted code by default.
- Run fork-code validation in
pull_request, where secrets are not in scope. - Use
pull_request_targetonly for repository-side actions that do not need to execute fork code. - If you truly need to check out fork code in a privileged workflow, make that an explicit exception after review.
name: fork-validation
on:
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci
- run: npm test
name: privileged-follow-up
on:
pull_request_target:
branches: [main]
jobs:
comment:
runs-on: ubuntu-latest
steps:
- run: echo "Repository-side action only"
The point is not to remove automation. The point is to keep untrusted code in a job that has no need for secrets, while privileged jobs stay on the repository side.
What the new default means
actions/checkout v7 now refuses unsafe fork PR checkout unless you opt in with allow-unsafe-pr-checkout: true.
That should read like a decision point, not a quick fix:
- if a workflow fails without the flag, inspect the trust model before you flip it on;
- if the job needs secrets, splitting the workflow is usually safer than checking out fork code;
- if you keep the unsafe opt-in, it should be documented and reviewed, not hidden in a copy-paste patch.
When opt-in can still make sense
There are edge cases where a privileged workflow really does need to inspect fork code. That can happen in a specialized DevEx pipeline or in automation with extra guardrails. Even then, treat the unsafe path as an exception and ask a few questions first:
- can the same result be achieved without checking out fork code here;
- are secret-bearing steps isolated from the untrusted code path;
- is there manual review or policy approval before enabling the exception;
- is the reason for the exception written down clearly.
If those answers are fuzzy, the new default is doing you a favor.
A quick decision tree
Use these three questions to evaluate an existing workflow:
- Does this job need secrets or a privileged token?
- Does it read code directly from a fork?
- Can validation and privileged action be split into separate workflows?
If the first two answers are yes, the current design is probably too trusting. If the first answer is no, prefer a less privileged trigger. If the third answer is yes, a split workflow is usually the cleanest option.
What to verify after migration
After moving to checkout v7, confirm three things:
- fork PRs no longer get a privileged checkout by default;
- trusted jobs do not execute untrusted code just because it is convenient;
- any
allow-unsafe-pr-checkoutexceptions are documented and limited.
Bottom line
GitHub did not take away your options. It removed the accidental one.
If you were already treating pull_request_target carefully, v7 gives you a better default. If your workflow depended on convenience over trust boundaries, this is the right moment to split the path and keep untrusted code away from privileged access.
Further reading
Quick checklist
- Identify every step that needs secrets or write access.
- Move fork-code validation into `pull_request` where possible.
- Keep privileged actions separate from code checkout.
- Treat `allow-unsafe-pr-checkout: true` as an exception that needs review.
- Verify that the workflow still follows repository policy after the change.
Plan a safe migration away from unsafe fork checkout
You are helping a team that already uses pull_request_target or workflow_run and sometimes checks out code from a fork. Review the workflow and return a short plan: 1. Which steps are trusted code, and which are untrusted code? 2. Can fork-code validation move to pull_request without secrets? 3. If a privileged job is required, which steps should stay separate from checkout? 4. When could allow-unsafe-pr-checkout: true still be justified? 5. What minimal rollout and verification plan would keep CI from breaking? Return a practical checklist for a repo owner or DevEx engineer.