On December 8, 2025, GitHub will change how the GitHub Actions pull_request_target event resolves workflow source and how environment branch protection rules are evaluated for PR-related events. The short version: pull_request_target will always run from your repository’s default branch, and environment rules will check the ref that’s actually executing. If you’ve relied on base-branch semantics or branch-name filters for environments, this will surprise you in production unless you adjust now. (github.blog)
What exactly changes on December 8, 2025?
Two behavioral shifts land at once—and both are security-motivated. (github.blog)
First, for pull_request_target, the workflow file and the ref used to run the job will always come from your default branch. Concretely, GITHUB_REF resolves to the default branch and GITHUB_SHA points to its latest commit when the run starts, regardless of which branch the PR targets. This closes a long‑standing class of incidents where outdated workflows on non‑default branches executed with elevated privileges. (github.blog)
Second, environment branch protection rules now evaluate against the executing reference for PR events. For pull_request and its review/comment variants, that executing ref is the PR’s merge ref (for example, refs/pull/123/merge). For pull_request_target, the executing ref is the default branch. Teams that match environments against branch names like release/* or feature/* will see jobs stop unlocking until those filters are updated. (github.blog)
Here’s the thing: these semantics finally align the security model with how maintainers expect privileged PR workflows to behave. You fix a risky workflow on main, and from December 8 forward, that fix governs pull_request_target runs—even if someone opens a PR against an old maintenance branch. (github.blog)
Should I stop using pull_request_target altogether?
If your PR workflow doesn’t need secrets or elevated permissions, yes—prefer pull_request with least‑privilege tokens. GitHub’s own guidance: avoid pull_request_target unless you truly need a privileged context, and never check out untrusted code in a privileged run. Use workflow_run or a post‑merge pipeline for deployments. (docs.github.com)
But abandoning pull_request_target outright isn’t always practical. Many teams use it for safe triage (labels, comments), for internal checks that require org‑only resources, or to manage contributor DX without exposing secrets. The key is to treat it as a narrowly scoped control plane, not a place to execute untrusted PR code. (docs.github.com)
What risks does pull_request_target carry with forks?
Because pull_request_target runs in the context of the base repository with access to secrets, it’s powerful—and attackers know it. A 2025 advisory in a popular open‑source repo documented how a PR‑triggered workflow could exfiltrate secrets and tamper with releases when paired with permissive checkout. GitHub’s tightening aims squarely at these recurring patterns. (github.com)
Where teams get burned on Dec 8
Let’s be candid about the common failure modes we’re already seeing in dry runs:
1) Environment filters stop matching. Your environment’s “Deployment branches” might be set to release/* or main/develop. After December 8, PR workflows evaluate against refs/pull/<n>/merge or the default branch (for pull_request_target). Result: secrets stay locked and jobs stall—or silently skip deployment steps—until you update filters. (github.blog)
2) Assumptions about refs break. Scripts that read config by walking GITHUB_REF or GITHUB_SHA and expect a base branch ref will suddenly read from the default branch (for pull_request_target) or the merge ref (for pull_request). That’s correct behavior under the new rules but wrong for your older scripts. (github.blog)
3) Monorepo release branches that acted like defaults. If you’ve been using release/* as de facto defaults for backports, note that pull_request_target will source only from the true default branch after the change. Move privileged logic to reusable workflows or post‑merge pipelines. (github.blog)
4) Hidden over‑privilege. Repos that set organization‑wide default write tokens or used blanket permissions: write-all will continue to work—but this is the moment to right‑size permissions. Keep GITHUB_TOKEN read‑only for PR checks and grant granular writes in a separate, trusted workflow. (docs.github.com)
Primary keyword check: GitHub Actions pull_request_target changes
You’ll see the biggest difference where GitHub Actions pull_request_target used to consult the PR’s base branch for workflow source. From December 8 onward, policy and code live only on the default branch for that event. That reduces the blast radius for forks and removes entire classes of “pwn‑request” scenarios built on outdated workflows. (github.blog)
A 90‑minute cutover plan you can run today
Block a focused window, open a test PR from a fork and from a branch in‑repo, and run this playbook end‑to‑end.
0–10 minutes: inventory and decide
Find every workflow that uses pull_request_target or depends on environments during PR events. If a job doesn’t truly need secrets, plan to move it to on: pull_request with least‑privilege permissions. If it does, keep pull_request_target but fence it: no checkout of untrusted code, and no secret‑bearing steps that touch PR artifacts. (docs.github.com)
10–30 minutes: refactor triggers and permissions
For PR checks, use on: pull_request and set permissions to the minimum (often contents: read). For post‑merge deploys, trigger via workflow_run from the default branch after PR checks succeed. Keep the deploy job in an environment with approvals or custom protection rules. (docs.github.com)
30–50 minutes: fix environment branch filters
In each environment, update “Deployment branches” to match the new reality: add refs/pull/*/merge for PR jobs and add your default branch explicitly for pull_request_target. If you’d rather not allow PR‑time deployments, make that explicit in docs and move deploys to post‑merge. (github.blog)
50–70 minutes: codify policy and reduce footguns
Add guardrails: a linter or CI step that fails if a workflow uses pull_request_target alongside actions/checkout of the PR head, or if a workflow grants write‑all permissions. Enable CodeQL scanning of workflow files, and consider OpenSSF Scorecards for extra eyes. (github.blog)
70–90 minutes: test both PR paths
Open two PRs: one from a fork, one from a branch on the same repo. Verify that PR checks run without secrets or writes, that environment secrets only appear in trusted contexts, and that post‑merge workflows deploy from the default branch once checks pass. Keep the test PRs around as canaries for the December 8 rollout. (github.blog)
Reference snippets (adapt to your repo)
Unprivileged PR checks
on: pull_request\npermissions:\n contents: read\njobs:\n pr-checks:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n with:\n fetch-depth: 1\n - run: npm ci\n - run: npm test -- --ci
Trusted post‑merge deploy (from default branch)
on:\n workflow_run:\n workflows: ["PR Checks"]\n types: [completed]\npermissions:\n contents: read\n deployments: write\njobs:\n deploy:\n if: ${{ github.event.workflow_run.conclusion == 'success' }}\n runs-on: ubuntu-latest\n environment: production\n steps:\n - uses: actions/checkout@v4\n - run: ./scripts/deploy.sh
These patterns avoid secrets during PR runs, keep writes behind an environment, and let you audit deploys in one place.
Dates and details that matter
December 8, 2025: change takes effect for pull_request_target semantics and environment evaluation on PR events. (github.blog)
December 4, 2025: macOS 13 hosted runner image is retired; brownouts already occurred on November 11, 18, and 25 (14:00–00:00 UTC). If your iOS builds still pin macos-13, expect failures. Migrate to macos-14, macos-15, or the new macos-15-intel label if you must stay on x86_64. (github.blog)
Cache policy enforcement (November 2025): eviction checks moved from daily to hourly for the 10 GB per‑repo cache cap. Normalizing cache keys matters more now to avoid churn. (github.blog)
People also ask
Does GITHUB_REF change for pull_request?
Yes. For pull_request, GITHUB_REF points to the merge ref (for example, refs/pull/123/merge), not the feature branch name. Many teams wrongly key logic off branch names; use inputs or explicit config instead. (docs.rs)
Can I keep using pull_request_target safely?
Use it for low‑risk triage and automation that needs elevated context, but do not check out untrusted code or run PR artifacts with secrets. Prefer post‑merge deploys. (docs.github.com)
What incidents motivated this?
Security advisories throughout 2025 show how permissive PR workflows could leak secrets or gain write access when paired with pull_request_target. The changes reduce that attack surface by rooting execution in the default branch and aligning environment checks to the executing ref. (github.com)
Let’s get practical: a quick audit checklist
Grab a teammate and tick through this today:
- List all workflows triggered by PR events. Flag any using
pull_request_target. - For each flagged workflow, confirm it doesn’t check out PR code or run scripts from it. If it does, migrate that work to
pull_requestwith read‑only tokens. - Set repository default token permissions to read for PR workflows; explicitly grant writes only where needed. (docs.github.com)
- Update environment “Deployment branches” to include
refs/pull/*/mergewhere appropriate and add your default branch forpull_request_target. (github.blog) - Add a CI policy check that fails on unsafe patterns (for example,
pull_request_target+ checkout ofgithub.event.pull_request.head.sha). - Enable CodeQL scanning for workflows; consider OpenSSF Scorecards. (docs.github.com)
Related playbooks and how we can help
If you need a concise, step‑by‑step fix, we published a field guide with sample policies and tests in our Dec 8 Survival Guide for pull_request_target. For broader CI/CD hygiene under the November/December changes (macOS runners, cache policy, reusable workflows), see our practical roundup in the Dec 8 Playbook. If your pipelines also publish to npm, plan the switchover with our last‑week CI cutover for npm tokens so you’re not juggling two emergencies at once. And if you’re mapping this alongside platform upgrades, our Node.js 24 LTS upgrade playbook lays out a proven, low‑drama approach.
What to do next (today, not tomorrow)
- Update environment branch filters and test a forked PR and an in‑repo PR.
- Split PR checks (unprivileged) from deploys (post‑merge), and make deploys run from the default branch only.
- Restrict GITHUB_TOKEN and stop checking out PR code in privileged workflows.
- Enable CodeQL scanning of workflows and add a CI policy check for unsafe patterns.
- Put a calendar reminder for December 8 at 09:00 your local time to run a smoke PR—no surprises.
Zooming out, this change is a net win for maintainers. It reduces the number of places an attacker can steer your pipeline and makes fixes on main authoritative. Ship the cutover now, communicate it in your README, and you’ll sleep fine on December 8.
