Security

actions/checkout v7 refuses fork PR code in pull_request_target

actions/checkout v7 refuses fork PR code in pull_request_target

You trust your CI to run untrusted code. Sit with that for a second. The whole point of a pull-request-triggered workflow is that anyone, anywhere, can hand you a payload and ask your build farm to do something with it. The trick — the bit every CI platform has been quietly bad at for years — is making sure "do something with it" doesn't silently become "do anything at all, with my secrets."

GitHub announced actions/checkout v7 on its changelog. The default changed in a small, opinionated way: when a workflow triggered by pull_request_target or workflow_run tries to fetch the head of a fork PR, the action now refuses. Failing closed. Finally.

"Pwn requests," briefly

GitHub frames the change as blocking "the most common form of pwn requests." If that phrase makes you wince, you've seen the pattern: a repository wants to label, lint, or comment on a contributor's pull request, so it reaches for pull_request_target — the trigger that runs in the base repository's context, with the base repo's GITHUB_TOKEN and secrets in scope. Then, almost by reflex, the workflow checks out the contributor's branch and runs something from it. A test. A linter. A build.

That is the moment it stops being a pull request and starts being a remote shell with credentials.

Same-repository pull requests aren't the issue (you already trust your own collaborators, mostly). The plain pull_request event runs in a permissionless fork context and isn't either. The danger has always lived in the unhappy marriage of "elevated token" and "attacker-controlled checkout." That marriage is what v7 annuls.

What v7 actually refuses

According to the changelog entry, v7 fails when a checkout step inside a pull_request_target or workflow_run workflow points at a fork — patterns such as refs/pull/<n>/head, a fork repository name, or a fork commit SHA. Nothing else changes. You can still use pull_request_target to label, comment, and run base-repo code; you just can't, by accident, drag the contributor's tree into your privileged job.

A rough sketch of the shape v7 now blocks:

on: pull_request_target

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          ref: refs/pull/${{ github.event.pull_request.number }}/head
          repository: ${{ github.event.pull_request.head.repo.full_name }}

Under the previous default that runs, with your secrets in scope, against whatever a contributor pushed. Under v7 it fails before the bytes ever land.

The opt-out, and why its name matters

There is an escape hatch — an allow-unsafe-pr-checkout input — and GitHub describes the flag as "intentionally named to be easy to spot in code review and static analysis." Read that twice. The name is the feature. A grep across an organisation's workflows for that string instantly enumerates every workflow that explicitly opted back into the dangerous pattern. Security teams who write detection rules for a living will love it; engineers who like their config to feel benign, less so.

That is the right trade. A well-named opt-out is worth more than ten lint rules.

The cutover, and what it doesn't fix

The changelog flags a backport: workflows pinned to a floating major tag will start getting the new enforcement on July 16, 2026, when GitHub backports the change to all currently supported major versions. Pinning to a resolved commit SHA buys you no escape from your own habits, but it does buy you a few weeks to read your own YAML.

What v7 does not do: stop you from curl | bash-ing a contributor's tarball inside a privileged job. It cannot. The default closes the most common door; the other doors are still your problem. Least-privilege permissions: blocks, scoped tokens, environment-protected secrets — none of that becomes optional just because the front door now has a lock.

How other CI systems draw the same line

The trust boundary GitHub just moved is universal — every CI platform has to answer the same question: what should a fork PR be allowed to do with my secrets? The answers vary in shape, not in spirit:

  • GitLab CI treats merge requests from forks as a distinct pipeline class and keeps protected variables behind explicit settings, on the assumption that fork code is untrusted by default.
  • CircleCI ships a per-project switch for whether forked PRs build at all, plus a separate switch for whether those builds inherit secrets — both off until you say otherwise.
  • Jenkins with the GitHub source plugin places fork PRs behind a build-approval gate the first time a contributor proposes a change, layered on top of org-level allowlists.
  • Drone-style schedulers simply do not pass secrets into fork builds unless a secret is explicitly marked fork-eligible.

Different shapes, same lesson: untrusted code wants your privileges, and a CI platform earns its keep by saying no on your behalf — without you having to remember which checkbox.

The kicker

For years the official answer to "is pull_request_target safe?" has been "yes, if you read the docs, never check out the PR head, and never use an action you didn't pin to a SHA." That isn't a default. That's a hazing ritual.

v7 isn't a fix for CI supply-chain security. It's the platform finally conceding that "don't shoot yourself in the foot" is its job, not yours. Take the upgrade. Grep your org for allow-unsafe-pr-checkout. And if you find it — be very sure you meant it.

Source: GitHub Changelog (github.blog)

Related
Security & supply chain

Pinning every CI action to a commit SHA is becoming the new minimum

A new write-up from the Cilium maintainers lays out a concrete playbook for locking down CI/CD dependencies — full-SHA pinning for every action, digest-pinned containers, vendored Go modules, and Renovate with a release-age cooldown. The pattern matters even if you do not ship eBPF for a living.

June 16, 2026
Security & supply chain

HCP Packer's enforced provisioners turn golden-image policy into a contract teams can't quietly skip

HashiCorp has added enforced provisioners to HCP Packer, letting platform and security teams centrally pin mandatory build steps onto every downstream image rather than trusting that the wiki page got read. The mechanism is the easy part; deciding whether your org actually wants policy this loud is the harder one.

June 17, 2026
Security & supply chain

Docker Content Trust gets a sunset date. The harder question is what you sign with next.

Docker has published a formal retirement plan for Docker Content Trust and the Notary v1 service at notary.docker.io, ten years after DCT shipped. The migration is mostly mechanical — the strategic question, about whether anyone downstream was actually verifying anything, is the part the guide cannot answer for you.

June 16, 2026

Turn this into your pipeline. Build it on Buddy.

Start free