GitHub is taking the decision away from you. On December 2, pull_request_target stops running by default in public repos on Free, Team and Enterprise Cloud. It's the right call, and it closes one door. The pwn request was never about a trigger: it's fork code running next to your secrets, and two other triggers can still set that up.
Some older write-ups still say November 2. That date moved. What's close is the first brownout: November 9, 16:00-18:00 UTC, then November 16 at the same time. In those windows, a workflow that would be blocked fails with an error annotation and doesn't run. Outside them the rule only evaluates: runs go ahead with a warning.
The Mechanism
pull_request runs a fork's code with a read-only token and no secrets. pull_request_target runs in the base repo's context, and GitHub's docs say what that costs: "the job receives the base repository's GITHUB_TOKEN and access to repository and organization secrets."
That's harmless until a step checks out the PR head and runs it. A build, a test, npm install, anything. As the docs put it, "The vulnerability is completed by the next step that runs code checked out into the current working directory."
This isn't a theoretical class. hackerbot-claw hit awesome-go, Trivy and RustPython through pull_request_target workflows in February and March. prt-scan opened well over 500 PRs across six accounts from March 11, under a 10% hit rate. Most hits exposed only short-lived GitHub credentials, but Wiz verified theft of AWS keys, Cloudflare API tokens and Netlify auth tokens. At that rate of attempts, a low hit rate is plenty.
None of this is new: GitHub's docs spell it out, and the pattern kept shipping. That's the part I'd underline: supply chain failures are a lack of agency, and when nobody acts, the platform eventually acts for you.
What the Block Doesn't Touch
The changelog names one event. Wiz, writing before the date moved, called the enforcement "a default, not a ban". What it leaves alone:
workflow_runisn't covered. A privileged workflow that runs fork code or trusts its artifacts has the same problem, and the docs say to treat those artifacts as untrusted data.issue_commentisn't covered. A privileged workflow that a comment can start, and that fetches and runs the PR's code, is the same pwn request with a different trigger.- Private and internal repos and GHES aren't covered.
- The opt-out is a policy that allows the event, optionally scoped to named workflow files. Reasonable, as long as you name the file and not the event.
actions/checkout v7 helps too: it refuses fork-PR checkouts in pull_request_target and PR-triggered workflow_run jobs. But that only covers checkouts made through that action. A git fetch in a run step doesn't care, and neither does gh. Socket calls it "a guardrail, not a complete solution".
So a team can pass December 2 with no failed runs and the same exposure, moved one trigger over.
What to Do Before November 9
List the workflows that run privileged on something a stranger can start:
That's a candidate list: it also matches comments and workflows that never touch PR code, and it misses reusable workflows called from elsewhere. Then for each file, ask one question: does any step execute something the PR author controls? That includes checked-out code, and also ${{ github.event.pull_request.title }} dropped into a run: block. Radware counted 83 attempts on that second one across 61 public repos on September 1, commands hidden in issue and PR titles, bodies and comments, with no fork code at all and no confirmed theft.
- It doesn't need secrets: move it to
pull_request. The docs say the same: "If additional secret access is not needed, use pull_request." - It needs secrets: split it. Untrusted work in
pull_requestwith a read-only token, the privileged step in a separate workflow that reads the artifact as data and never executes it. Pass event fields throughenv:, and keep its secrets in an environment with required reviewers, not at repo level. - It only labels or comments and never runs PR code: this is the legitimate case. Allow that named file, not the event.
The Tradeoff
Expect breakage that doesn't look like breakage. actions/labeler#980 points out that workflows set up the way the README suggests "will stop running", and that "maintainers may not notice", because the run is blocked before any job starts. A silent labeler is a small loss. A silent required check or preview deploy is a bad afternoon. That's what the brownouts are for, so watch them.
And the split isn't free. It's more YAML, and workflow_run is itself a sharp tool: it's safe only while nobody treats that artifact as code. For now, you're trading a loud default for a discipline you have to keep.
Take the block. It isn't your fix.