BYBOWU > Blog > Web development

Dec 8: GitHub Actions pull_request_target Changes

blog hero image
On December 8, 2025, GitHub will change how pull_request_target and environment branch protections work. If you rely on PR-triggered workflows, this can silently break deployments or, worse, leak secrets through unsafe patterns. Here’s the practical read you can hand to your platform team today: what’s changing, what breaks, and the exact migration playbook we’re using with clients. You’ll get a before/after mental model, code examples, and a short checklist to keep CI moving while ti...
📅
Published
Nov 16, 2025
🏷️
Category
Web development
⏱️
Read Time
10 min

On December 8, 2025, GitHub will roll out material changes to GitHub Actions pull_request_target changes and how environment branch protection rules are evaluated for pull‑request‑related events. If your CI depends on PR triggers, this cutover can block deployments or expose secrets if you’ve mixed privileged tokens with untrusted pull request code. Let’s translate the announcement into actions you can take right now.

Illustration of a developer reviewing GitHub Actions workflow diagrams

What’s actually changing on December 8?

There are two big shifts.

First, for pull_request_target, the workflow file and the checkout commit will always come from the repository’s default branch. That means refs and commits used during execution point at the default branch, not whatever branch was set as the PR’s base. Practically, GITHUB_REF resolves to the default branch, and GITHUB_SHA points to its latest commit. This closes a class of issues where outdated workflows on secondary branches were still executing for pull_request_target events.

Second, environment branch protection rules now evaluate against the ref that actually executes, not the PR head. For the pull_request family (pull_request, pull_request_review, pull_request_review_comment), the evaluation happens on refs/pull/<number>/merge. For pull_request_target, environment rules evaluate against the default branch. If your environment rules were keyed to specific branch names under the old semantics, they may stop matching.

Why GitHub is doing this

Here’s the thing: pull_request_target is powerful and risky. It runs in the base repository’s context, has broader permissions by default, and can access secrets—even on PRs from forks—if you configure it that way. Historically, some teams combined pull_request_target with checkouts of PR code and then executed scripts. That’s where attackers look for openings to exfiltrate tokens or push unwanted commits. Forcing workflow source to the default branch and aligning environment evaluation to trusted refs lowers the blast radius.

Will my workflows break?

Maybe. The most common breakages we’re seeing in audits are:

  • Environment rules that no longer match. Teams often used “Selected branches” like release/* for environments. With PR events now evaluating against refs/pull/<number>/merge, those rules won’t match without an explicit refs/pull/*/merge pattern or an alternative approach.
  • Assumptions about GITHUB_REF/GITHUB_SHA. Jobs or scripts that derive version tags, changelog ranges, or cache keys from the base branch ref will observe different values on and after December 8.
  • Insecure pull_request_target usage. If you check out PR head code and execute it in a job with write tokens or secrets, you’re already on thin ice. The new behavior won’t fix that by itself; it just helps prevent stale workflow files from being executed.

How to adapt: a practical migration playbook

If you have one hour, you can de‑risk most repos with this flow. This mirrors what we do for clients who ask us to come in late in the cycle and “make it not break Monday.”

1) Inventory and classify your PR workflows

Search for on: [pull_request, pull_request_target, pull_request_review, pull_request_review_comment]. For each workflow, label it as:

  • Privileged (needs write permissions or secrets to comment, label, deploy, update checks).
  • Unprivileged (pure CI: build, test, lint, no secrets required).

2) Default to pull_request for unprivileged jobs

Keep untrusted code quarantined. Use the pull_request trigger with least‑privilege GITHUB_TOKEN permissions. If you need to post results back (coverage, status comments), pass artifacts and hand off to a separate privileged workflow (see step 3).

3) Split privileges using the two‑stage pattern

Stage A runs on pull_request and builds/tests untrusted code, uploading artifacts. Stage B runs on workflow_run (triggered by Stage A completion), has write permissions and secrets, downloads artifacts, and posts comments or updates external systems. This keeps secrets away from untrusted code while preserving contributor UX.

4) If you must keep pull_request_target, lock it down

Constrain it to trusted contexts only. Some teams gate execution behind a maintainer‑applied label (for example, safe-to-test) or restrict steps to the default branch. Do not run PR‑supplied scripts in that job. Treat PR content as data, not executable.

5) Update environment branch protection rules

Adjust environments used by PR workflows:

  • For pull_request and related events, include a rule that matches refs/pull/*/merge if you want those jobs to pass protection and access environment secrets (only recommended for trusted repositories).
  • For pull_request_target, ensure the environment allows the default branch, since evaluation now runs against it.

Alternatively, move deployments off PR triggers entirely and require workflow_dispatch or protected branch merges for production environments.

6) Tighten default permissions

In workflow or org settings, set default permissions: read-all and explicitly grant per‑job scopes when necessary. Pin all third‑party actions to commit SHAs, not tags. When possible, avoid checking out PR head code in privileged jobs.

7) Validate artifact integrity

If you rely on artifacts flowing from unprivileged to privileged jobs, ensure you verify digests and expected contents before acting on them. Don’t consume arbitrary artifacts uploaded from forks without explicit checks.

People also ask: short answers

Do I still need pull_request_target?

Sometimes. If you only need to label, assign, or comment—and you truly don’t run PR code—pull_request_target can be fine. For anything that executes contributor code or uses secrets, prefer pull_request plus workflow_run.

What happens to Dependabot PRs?

Dependabot is treated like a forked PR for permissions. Keep its workflows unprivileged and avoid exposing secrets in the initial PR job. Use the two‑stage handoff if you need to report rich results back to the PR.

Will this change affect GitHub Enterprise Server?

The December 8 rollout targets GitHub.com. GHES timelines can differ; check your release notes before relying on the behavior there. If you mirror workflows between Cloud and GHES, align to the stricter model anyway—it’s more secure.

Before/after: mental model for refs and environments

Previously, pull_request_target could execute using workflow files sourced from any base branch in the repo. After the change, it always sources from the default branch. Previously, teams often assumed environment rules evaluated against human‑friendly branch names. After the change, PR events evaluate against refs/pull/<number>/merge (for the pull_request family) or the default branch (for pull_request_target), which is why your old patterns may stop matching.

A secure reference implementation you can copy

Use this as a blueprint. It keeps untrusted code away from secrets, works for forks, and plays nicely with the December 8 semantics.

Stage A — PR CI (unprivileged): Build, test, and export artifacts.

name: PR CI

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: Install
        run: npm ci
      - name: Test
        run: npm test -- --json --outputFile=report.json
      - name: Upload report
        uses: actions/upload-artifact@v4
        with:
          name: test-report
          path: report.json

Stage B — Post results (privileged): Comment on the PR with results from artifacts only.

name: PR Reporter

on:
  workflow_run:
    workflows: ["PR CI"]
    types: [completed]

permissions:
  contents: read
  pull-requests: write

jobs:
  comment:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: test-report
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Verify artifact and comment
        run: |
          test -f report.json || exit 1
          echo "CI passed. See details in report.json" > body.txt
      - name: Post PR comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const body = fs.readFileSync('body.txt', 'utf8');
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.payload.workflow_run.pull_requests[0].number,
              body
            });

Note the absence of a checkout of PR code in the privileged stage. Also note the explicit head.sha in Stage A to avoid time‑of‑check/time‑of‑use surprises.

Engineer editing YAML workflows on a laptop

Updating environment branch protection rules

With the new evaluation model, you have three sensible options for environments referenced during PR jobs:

  • Don’t use environments on PR jobs. Keep environments for post‑merge or manual deploy jobs only. Simple and safe.
  • Allow the PR merge ref explicitly. Add a pattern for refs/pull/*/merge in environments that need to run during PR validation (for example, a non‑prod preview). Combine with required reviewers to avoid automatic secret exposure.
  • Restrict to the default branch. For pull_request_target, that’s now the evaluation ref anyway. Be explicit and add your default branch to the allowed list.

If your team previously set “Protected branches only,” revisit whether that still achieves your intent for PR workflows, because the evaluation ref is no longer a human‑named branch.

Risk scenarios to kill before December 8

Based on real audits, here are the patterns that most often lead to compromise:

  • Running PR‑supplied scripts in privileged jobs. Especially package manager scripts that execute lifecycle hooks (npm install, pip install, bundle install).
  • Using pull_request_target to deploy previews. It’s tempting but dangerous. Use a separate job that deploys from a trusted ref or through a manual gate.
  • Broad default permissions. Repositories with GITHUB_TOKEN write across the board and no job‑level override.

Timeline, scope, and who should care

The change lands on Monday, December 8, 2025 (GitHub.com). If you run GitHub Enterprise Server, verify your specific version’s notes before expecting identical behavior. Any org that accepts external contributions or uses PR‑driven deploys needs to review workflows. If your repos are private and all contributors are employees, take this chance to simplify permissions anyway.

What to do next (this week)

  • Audit: Search for pull_request_target and list environments referenced by PR jobs.
  • Refactor: Split privileged and unprivileged work using the two‑stage pattern above.
  • Reconfigure: Update environment rules to include refs/pull/*/merge where appropriate, or move deploy steps out of PRs.
  • Right‑size permissions: Set org default permissions: read-all; grant per‑job scopes explicitly; pin actions to SHAs.
  • Dry run: Rehearse on a throwaway repo with forks to confirm behavior before the 8th.

Related deep dives from our team

We’ve been preparing clients for this cutover for weeks. If you want more battle‑tested examples and checklists, read our focused guides:

Dec 8 Deadline: what to fix in pull_request_target
A survival guide for the cutover
Understanding the Dec 8 cutover mechanics

If you need help implementing this at scale across dozens of repos, our engineering services team can do the audit and migration hands‑on. Browse a few recent CI/CD projects in our portfolio, or just reach out via contacts.

Flowchart of a two‑stage GitHub Actions workflow

The bottom line

The December 8 update nudges everyone toward a safer default: trusted workflow sources and ref‑aligned environment checks. Treat it as an opportunity to simplify permissions, remove fragile branch‑name filters, and separate untrusted code from secrets. If you make the changes above this week, you’ll glide through the cutover and end up with a sturdier pipeline for 2026.

Written by Viktoria Sulzhyk · BYBOWU
2,987 views

Get in Touch

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

Email Us

[email protected]

We'll respond within 24 hours

Call Us

+1 (602) 748-9530

Available Mon-Fri, 9AM-6PM

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

💻
🎯
🚀
💎
🔥