BYBOWU > Blog > Web development

GitHub Actions pull_request_target: Fixes by Dec 8

blog hero image
On December 8, 2025, GitHub will change how pull_request_target and environment branch protections work. If your repos comment on PRs, label issues, or deploy from PR events, you can’t wait—some jobs may silently stop matching env rules, and others may run with different refs than you expect. Here’s the practical, copy‑pasteable playbook we’re using with clients to audit workflows, patch branch filters, and ship safe changes before the deadline. We’ll also flag runner shifts (macO...
📅
Published
Nov 14, 2025
🏷️
Category
Web development
⏱️
Read Time
10 min

GitHub Actions pull_request_target: Fixes by Dec 8

On December 8, 2025, GitHub will change how the GitHub Actions pull_request_target event and environment branch protections are evaluated for pull‑request‑related workflows. If you rely on PR automation—comment bots, labelers, preview deployments, or status checks tied to environments—this update changes which workflow ref executes and which branch patterns your environment rules match. Ignore it and you risk broken deploy gates, missing secrets, or automation that quietly stops firing.

Here’s the thing: the update hardens security and closes long‑standing edge cases, but it also breaks assumptions many teams have baked into their pipelines. Let’s get practical and lock this down before the Friday rush.

Illustration of PRs flowing into a protected main branch in CI/CD

What exactly is changing on December 8?

Two shifts matter most.

1) pull_request_target now always executes from the default branch

Starting December 8, workflows triggered by pull_request_target will always use the repository’s default branch for workflow source and reference. That means:

  • GITHUB_REF resolves to the default branch.
  • GITHUB_SHA points to the latest commit on the default branch.

Previously, GitHub could run the workflow from the PR’s base branch (which might not be your default). If you depended on non‑default base branches, or you expected older workflow versions on release branches to run, that assumption ends.

2) Environment branch protections evaluate against the execution ref

Environment branch rules attached to PR events will evaluate against the ref that actually executes the workflow—not the PR head. Concretely:

  • pull_request, pull_request_review, and pull_request_review_comment evaluate against refs/pull/<number>/merge.
  • pull_request_target evaluates against the default branch.

That’s a breaking change if you use environment branch filters like feature/* or release/*. Those patterns won’t match refs/pull/123/merge or a default branch ref, so your environment may no longer unlock secrets or approvals for PR jobs.

Why GitHub is doing this (and why you should too)

Security. For years, teams misused pull_request_target by checking out attacker‑controlled PR code and then running it with write‑scoped GITHUB_TOKEN or with environment secrets. This led to real‑world exfiltration incidents, cache poisoning, and full repo compromise. By pinning execution to the default branch and aligning environment checks to the execution ref, GitHub removes an entire class of “pwn request” surprises.

It also aligns with better defaults elsewhere: short‑lived tokens, stricter token scopes, and most recently the OIDC token including a check_run_id claim for tighter, attribute‑based access control to your internal platforms.

Field notes: common breakages we’re already seeing

We’ve been dry‑running these changes across monorepos and public OSS projects. Here are the most frequent failure modes:

  • Environment rules stop matching: Filters like branches: ["release/*"] won’t match refs/pull/123/merge. Jobs that used to unlock secrets: inherit or approvals now run without access—or fail.
  • Ref‑dependent scripts break: Scripts that read ${GITHUB_REF} or ${GITHUB_SHA} to compute Docker tags or cache keys now behave differently. You’ll see cache misses, wrong tags, or clobbered artifacts.
  • Unnecessary use of pull_request_target: Many repos use pull_request_target simply to comment on PRs from forks. That no longer requires elevated permissions—and you probably don’t want secrets there anyway.
  • Fork workflows invoking dangerous steps: A few pipelines still check out ${{ github.event.pull_request.head.sha }} and run tests with write‑scoped tokens or environment secrets. That’s still hazardous, just less likely to be mis‑ref’d after Dec 8.

Quick wins before the deadline

If you only do three things this week, do these:

  1. Replace pull_request_target where possible. If a workflow doesn’t need secrets or write permissions, switch to on: pull_request. Give the job a read‑only token and move on.
  2. Patch environment filters. For PR events, add patterns that match refs/pull/*/merge. For pull_request_target-based jobs, ensure your environment rules allow the default branch.
  3. Lock permissions down. Set permissions: read-all at the workflow level, then grant write only to individual steps that truly need it. This single change stops a lot of exfiltration paths.

Copy‑paste audit: find risky workflows in minutes

Drop this command in the repo root to audit workflows that use pull_request_target and might check out untrusted code:

rg -n "on:\s*pull_request_target|uses:\s*actions/checkout|secrets:\s*inherit|permissions:" .github/workflows \
  | sed 's/^/WORKFLOW: /'

Flag anything that:

  • Runs on pull_request_target and also checks out PR head code.
  • Uses secrets: inherit with a PR trigger.
  • Relies on GITHUB_REF or GITHUB_SHA for tags or cache keys without normalization.

How to rewrite a risky PR workflow

Here’s a safer split‑pattern we recommend. One workflow runs on pull_request with no secrets; a second, privileged workflow runs on workflow_run after the PR checks pass. This avoids running untrusted code with secrets.

# .github/workflows/pr-ci.yml
name: PR CI (no secrets)
on:
  pull_request:
    types: [opened, synchronize, reopened]
permissions: read-all
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - name: Install deps
        run: npm ci
      - name: Run tests
        run: npm test

# .github/workflows/priv-deploy.yml
name: Privileged Deploy (after checks)
on:
  workflow_run:
    workflows: ["PR CI (no secrets)"]
    types: [completed]
permissions:
  contents: read
  id-token: write  # for OIDC
concurrency: deploy-${{ github.ref }}
jobs:
  deploy:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    environment: preview
    steps:
      - uses: actions/checkout@v4
      - name: Assume cloud role via OIDC
        run: echo "Assume role & deploy"

This design moves secrets to a post‑check workflow that never executes PR‑supplied scripts directly.

Updating environment branch protections

Because PR events now evaluate environment rules against the execution ref, adjust your environment filters accordingly. For environments used by pull_request jobs, add patterns that match the merge ref:

# Example (Organization settings → Environments → preview)
# Allow list of branches & tags:
refs/pull/*/merge
main
release/*

For environments used by pull_request_target, ensure your default branch is allowed. In many orgs, that’s main. If you had patterns like feature/* or bugfix/* only, the environment will no longer unlock on PR events.

Normalizing refs for tags and caches

Tools that tag images or compute cache keys from GITHUB_REF and GITHUB_SHA will behave differently after December 8. Normalize inputs explicitly:

- name: Normalize ref for PRs
  id: ref
  run: |
    if [[ "${GITHUB_REF}" =~ refs/pull/.*/merge ]]; then
      echo "name=ref_slug::pr-${GITHUB_REF#refs/pull/}-$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_OUTPUT
    else
      echo "name=ref_slug::$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-')-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT

- name: Build image
  run: docker build -t ghcr.io/acme/app:${{ steps.ref.outputs.ref_slug }} .

That tiny helper avoids surprise tag churn when PR merge refs or default‑branch SHAs change.

Developer editing a GitHub Actions YAML file on a laptop

Do you still need pull_request_target?

Great question. In most repos, no. Use pull_request for tests and static analysis with a read‑only token, then promote via workflow_run or a manual workflow_dispatch that runs in a controlled environment with OIDC. Keep pull_request_target only if you must interact with the repo (e.g., applying labels from forks) and you’ve proven you don’t check out or execute untrusted code.

What about forks and contributors?

Forked PRs will continue to trigger pull_request just fine. If you need to add labels or comments from forks, scope the GITHUB_TOKEN to contents: read and grant write to pull-requests: write for the single step that posts a comment. Never run contributor‑supplied scripts in that job.

OIDC hardening you’ll actually use

With the OIDC token now including check_run_id, platform teams can design policies that bind cloud roles to a specific job identity. On the cloud side, require both run_id and check_run_id, the repo, and a branch condition (e.g., default branch only) before issuing temporary credentials. That makes lateral movement via replay or cross‑repo abuse far harder.

Heads‑up: runner changes you’ll trip over next

Two runner updates matter while you’re touching CI anyway:

  • macOS 13 retirement: The last brownout windows hit on November 18 and November 25, 2025. The macos‑13 images retire on December 4, 2025. Migrate to macos‑15 / macos‑latest (arm64) or the new macos‑15‑intel if you truly need x86_64.
  • M2 macOS runners are GA: If you build for iOS or do heavy simulators, the macos‑15‑xlarge and macos‑latest‑xlarge labels are a quick performance win.
  • Node24 migration clock: Actions will default to Node24 starting March 4, 2026. If your pipeline pins older actions or relies on Node20 behavior, start testing with FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true now.

A 60‑minute checklist to be done by lunch

  1. Inventory: List workflows with pull_request_target and any that reference GITHUB_REF/GITHUB_SHA. Note environments used by PR jobs.
  2. Replace triggers: Move test/build workflows to pull_request with permissions: read-all. Use workflow_run for privileged follow‑ups.
  3. Patch environments: Add refs/pull/*/merge to PR environments. Ensure default branch is allowed for any pull_request_target jobs that remain.
  4. Normalize refs: Add a small step to compute stable tags and cache keys.
  5. Scope permissions: Set repository defaults to read‑only and grant per‑step writes sparingly.
  6. Test on a fork: Open a draft PR from a fork and validate comments, labels, and any preview deploys still behave.
  7. Update runners: Swap macos‑13 for macos‑15 or macos‑15‑intel; consider M2 xlarge for simulator heavy jobs.

People also ask

Should I stop using pull_request_target entirely?

Not necessarily. Keep it for workflows that must act on the base repository in response to forked PRs and that do not check out or execute PR code. If you need to run untrusted code, use pull_request plus a separate privileged workflow.

Do I need environments to use secrets with PRs?

It’s safer to avoid secrets in PR jobs. If you must, bind them to environments with strict reviewers and updated branch filters. Use OIDC to mint short‑lived credentials only on trusted refs.

Will my existing branch rules still work?

If they match refs/pull/*/merge for PR events and the default branch for pull_request_target, yes. Otherwise, expect surprises.

Where this fits in your broader CI/CD strategy

Zooming out, these changes nudge you toward a clearer separation of concerns: untrusted contributor code runs with read‑only tokens and no secrets; privileged operations happen after policy checks, on trusted refs, with just‑in‑time credentials. It’s a healthier model than trying to make one do‑everything workflow safe.

If you want a deeper dive into rollout sequencing and week‑by‑week task lists, we laid out pragmatic timelines in our recent posts what to fix this week and the companion ship the fixes now. If you still have legacy macOS runners in play, grab our macOS 13 deprecation guide. And if you’d rather have a partner audit/patch your org’s CI, our services page outlines how we engage fast.

Isometric illustration of OIDC-secured deployment flow

What to do next (today and tomorrow)

Today is Friday, November 14, 2025. You’ve got three business weeks before December 8.

  • Today: Replace low‑risk pull_request_target uses, patch environment filters, and merge. Run a forked PR test.
  • Early next week: Normalize refs, scope permissions, and flip any macOS 13 labels. Trial M2 runners where builds are slow.
  • Before Thanksgiving: Move privileged PR steps to workflow_run or workflow_dispatch. Add OIDC policies that include check_run_id and default‑branch conditions.
  • Week of Dec 1: Enable organization‑wide defaults for read‑only tokens and review remaining exceptions.

Make these changes once, and you won’t scramble every time a PR lands. Your checks will be faster, safer, and easier to reason about—and that’s the kind of reliability your team and customers can feel.

Written by Viktoria Sulzhyk · BYBOWU
3,232 views

Work with a Phoenix-based web & app team

If this article resonated with your goals, our Phoenix, AZ team can help turn it into a real project for your business.

Explore Phoenix Web & App Services Get a Free Phoenix Web Development Quote

Get in Touch

Ready to start your next project? Let's discuss how we can help bring your vision to life

Email Us

hello@bybowu.com

We typically respond within 5 minutes – 4 hours (America/Phoenix time), wherever you are

Call Us

+1 (602) 748-9530

Available Mon–Fri, 9AM–6PM (America/Phoenix)

Live Chat

Start a conversation

Get instant answers

Visit Us

Phoenix, AZ / Spain / Ukraine

Digital Innovation Hub

Send us a message

Tell us about your project and we'll get back to you from Phoenix HQ within a few business hours. You can also ask for a free website/app audit.

💻
🎯
🚀
💎
🔥