Skip to content

Cybersecurity · Supply Chain Security

GitHub Actions Just Closed the Pwn Request Window: What actions/checkout v7 Changes

Enforcement of actions/checkout's new pull_request_target protections landed July 20, 2026, closing the exact hole the AsyncAPI attack used six days earlier. Here's what changed, who needs to act, and how to check your own workflows.

Prathviraj Singh

Prathviraj Singh

5 min read

GitHub Actions Just Closed the Pwn Request Window: What actions/checkout v7 Changes

Sponsored

Share

If your CI pipeline uses actions/checkout and you haven’t touched it in months, it changed underneath you this week anyway. As of Monday, July 20, 2026, GitHub finished rolling out enforcement that makes actions/checkout refuse to fetch pull request code from a fork when it’s running inside a pull_request_target or workflow_run workflow. That’s the exact pattern behind the AsyncAPI Generator compromise six days earlier, and it’s not a coincidence that the enforcement date sits right after it.

The attack this closes

pull_request_target is a GitHub Actions trigger built for a real need: workflows that need to comment on a pull request, apply labels, or run a privileged check against a PR from a fork, without giving that fork’s code direct access to secrets. To make that work, the trigger runs with the target repository’s GITHUB_TOKEN and any configured secrets, even though the PR itself might come from an untrusted stranger.

The trouble starts when a workflow does both things at once: trigger on pull_request_target, and then check out and execute the PR’s actual code, whether directly or through a build step, a test runner, or a dependency install. At that point the fork’s code is running with the target branch’s privileges. That combination has a name in the security community, a pwn request, and it’s been the root cause of a string of real incidents, most recently the July 14 AsyncAPI attack, where a pull_request_target misconfiguration let an attacker steal a privileged bot token and push malicious packages to npm under a namespace with millions of weekly downloads.

What changed in checkout v7

actions/checkout v7 became generally available on June 18, 2026, and it changed the default behavior for exactly this case: when it detects it’s running inside a pull_request_target workflow (or a workflow_run workflow triggered by a pull request event), it now refuses to check out the fork’s head commit unless the workflow explicitly opts back in.

# Before: silently checks out the fork's PR code under target-branch privileges
on: pull_request_target
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ github.event.pull_request.head.sha }}

# After v7's default: this now fails the checkout step, by design
      - uses: actions/checkout@v7
        with:
          ref: ${{ github.event.pull_request.head.sha }}

# The explicit opt-out, for workflows that genuinely need this
      - uses: actions/checkout@v7
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          allow-unsafe-pr-checkout: true

The important part isn’t the new flag, it’s that the unsafe path now requires a line of code a reviewer can flag. Before, a workflow could ship this misconfiguration silently in a file most contributors never read closely. Now it takes a deliberate, visible opt-out.

Who this actually affects

GitHub backported the protection to every currently supported major version of actions/checkout except v1. The rollout has two very different outcomes depending on how your workflows pin the action:

How you pin actions/checkoutWhat happens
Floating major tag (@v4, @v5, @v6, @v7)You already have the fix. No action needed.
Pinned to a specific SHANot affected automatically. Needs a manual bump to a patched SHA.
Pinned to an exact minor or patch versionNot affected automatically. Needs a version bump through Dependabot or your normal update process.
Still on actions/checkout@v1Not covered by the backport at all. If you’re on v1 for any reason, that’s worth fixing regardless of this specific change.

Most teams use the floating major tag pattern, uses: actions/checkout@v4 and similar, specifically because it’s the convention GitHub’s own docs and templates use. If that’s you, you got this fix automatically, likely without noticing. If your organization pins to exact SHAs for supply-chain reasons, which is otherwise good practice, this is the one case where that pinning discipline means you have to go get a fix rather than receive it passively. Check your Dependabot or Renovate configuration is actually tracking actions/checkout version bumps, not just ignoring them because “it’s just a checkout step.”

What to actually check this week

  1. Search your workflows for pull_request_target and workflow_run. grep -rn "pull_request_target" .github/workflows/ in any repo you maintain. Each match is a workflow that runs with elevated privileges against untrusted input by design.
  2. For each match, check whether it also checks out the PR’s head ref. Look for ref: ${{ github.event.pull_request.head.sha }} or similar inside the same job. If it’s there, that job was checking out fork code with target-branch secrets before this week, and either the update fixed it silently or you’ll see a checkout failure that tells you the workflow needs allow-unsafe-pr-checkout and a closer look.
  3. If you find allow-unsafe-pr-checkout after upgrading, treat it as a flag for review, not a fix. The opt-out restores the old behavior. That might be correct for a workflow that only builds a PR preview and never touches a real secret, and it might be exactly the misconfiguration this whole change exists to prevent. Read the rest of that job before deciding.
  4. Confirm which secrets a pull_request_target job actually has access to. The checkout fix closes the specific step where fork code executes with those secrets. It doesn’t audit what those secrets can do. A job with id-token: write and a publish permission is worth a second look regardless of how it checks out code, following the same logic we covered in setting up npm trusted publishing to remove standing credentials in the first place.

The gap between “GitHub shipped a fix” and “your workflows actually use it” is exactly where the AsyncAPI attack happened. If your team runs any CI/CD pipeline audit as part of routine infrastructure work, this is a fifteen-minute check worth adding to it this week rather than assuming a floating version tag already covered you.

Frequently asked questions

What is a pwn request attack?
It's what happens when a GitHub Actions workflow triggered by pull_request_target checks out and runs code from the pull request itself. That trigger runs with the target repository's GITHUB_TOKEN, secrets, and branch protections, even for a PR from an untrusted fork. If the workflow also pulls in and executes the PR's code, an attacker gets their code running with the target branch's full privileges, not the fork's. That combination is called a pwn request, and it has caused multiple real supply-chain compromises.
Do I need to change anything in my workflows?
Depends on how you pin actions/checkout. If your workflow references a floating major tag like actions/checkout@v4 or @v5, you picked up the new protection automatically once GitHub backported it, no edit needed. If you pin an exact SHA, a minor version, or a patch version, you need to bump that pin yourself, through Dependabot or your normal dependency update process, to get the fix.
What if my workflow actually needs to check out PR code under pull_request_target?
There's a documented escape hatch: passing allow-unsafe-pr-checkout to actions/checkout restores the old behavior. Some legitimate workflows, like ones that build and label a PR's changes for a bot to comment on, do need this. The point of the new default isn't to ban the pattern outright, it's to make it something a maintainer has to deliberately opt into and can spot in a code review, instead of something that silently ships in a workflow file nobody double-checked.
How does this relate to the AsyncAPI attack?
Directly. Microsoft Threat Intelligence's writeup on the July 14, 2026 AsyncAPI Generator compromise identified the root cause as a pull_request_target workflow that checked out and ran fork PR code, letting the attacker steal a privileged token and push malicious npm packages. GitHub's enforcement deadline for this exact protection, originally set for July 16, was pushed to July 20 and then landed as scheduled. It's about as direct a before-and-after as CI security gets: the attack that made the case, and the fix six days later.

Sources

Sponsored

Sponsored

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored