Tag: pull_request_target

  • GitHub Actions Will Block pull_request_target by Default on December 2 (2026)

    GitHub Actions Will Block pull_request_target by Default on December 2 (2026)

    Takeaway: GitHub said in a November 2, 2026 changelog that starting December 2, 2026, GitHub Actions will block pull_request_target events by default in all public repositories, unless an Actions event policy explicitly allows them. Enforcement had previously been scheduled for November 2 and was delayed. Before the permanent switch, GitHub will run two short “brownouts” — November 9 and November 16, 2026, each from 16:00–18:00 UTC — when the default rule temporarily behaves as if it were already enforced. During those windows, blocked workflow attempts create failed runs with an error annotation and do not execute. Private and internal repositories are not affected, and neither is GitHub Enterprise Server. GitHub’s own guide to using pull_request_target securely explains why the trigger is powerful, how people commonly break its safety model, and how to review policy insights before the first brownout.

    This is a CI-policy story for maintainers of public repos, not another secrets-in-the-wild roundup like Claude Code settings files on GitHub, and not a recap of GPT-6 Cyber or OpenAI’s Linux kernel vulnerability pipeline. The hook is practical: the first brownout is on November 9 (00:00–02:00 on November 10 in Asia/Shanghai; 08:00–10:00 a.m. Pacific). If a public repository still relies on pull_request_target without an allowing policy, those two hours are a live fire drill.

    The dates that matter

    MilestoneWhenWhat GitHub says happens
    Original enforcement targetNovember 2, 2026Delayed; the changelog says enforcement was previously scheduled for that day
    Evaluate mode (now)Until December 2, except during brownoutsMatching runs continue, but policy insights show which ones the default rule would block
    First brownoutNovember 9, 2026, 16:00–18:00 UTCDefault rule temporarily enforced; blocked attempts fail with an error annotation and do not run
    Second brownoutNovember 16, 2026, 16:00–18:00 UTCSame temporary enforcement
    After each brownoutImmediately afterwardThe default rule returns to evaluate mode; workflows can run again with warnings
    Permanent default blockDecember 2, 2026pull_request_target is blocked in public repos that still rely on the default policy, unless an applicable Actions event policy allows it

    GitHub introduced the default rule through workflow execution protections. For public repositories that do not already have an applicable Actions event policy, GitHub adds a default policy that blocks workflows triggered by pull_request_target. That default does not replace a policy you already configured, and it does not apply to private or internal repositories.

    Who is in scope

    Repository or productAffected by the default block?Notes from GitHub
    Public repos on GitHub Free, Team, or Enterprise CloudYesThis is the population named in the changelog
    Private repositoriesNoUnchanged by this default rule
    Internal repositories (Enterprise Cloud)NoUnchanged by this default rule
    GitHub Enterprise ServerNoExplicitly excluded
    Repos that already have an applicable Actions event policyThe new default does not replace that policyYour existing allow/deny rules remain the ones that apply

    If every workflow you care about already uses pull_request rather than pull_request_target, you may have nothing to change — the default block is then doing the job GitHub intends. The people who need to act are maintainers whose public automation still depends on the privileged trigger: labeling or triaging pull requests from forks, posting authenticated status checks, or any other job that was written to run with the base repository’s secrets.

    What pull_request_target actually does

    GitHub’s security guide draws a sharp line between pull_request and pull_request_target. A pull_request workflow (and the related review events) runs the workflow file from the pull request’s merge commit. For a fork, that commit is controlled by someone who does not have write access to your repository. GitHub therefore gives those jobs a read-only GITHUB_TOKEN, withholds other secrets, and applies fork-approval policies so the untrusted workflow cannot quietly spend your secrets or your compute.

    pull_request_target flips the trust model. The workflow file — and a default actions/checkout that does not pin another ref — comes from the base repository’s default branch, not from the pull request. Because only that already-trusted workflow is supposed to run, GitHub grants the job the same class of trust it gives collaborator-triggered events such as push: the base repository’s GITHUB_TOKEN and access to repository and organization secrets.

    That combination is why the trigger exists. Automation that must comment on a fork’s pull request, apply labels, or publish an authenticated check often cannot do its job with a read-only, secret-less token. It is also why a mistake is expensive. The safety property holds only while the privileged job treats the pull request as data to inspect, never as code to execute.

    Why GitHub is changing the default

    The changelog’s one-sentence rationale is the same idea as the longer security guide: pull_request_target runs in the base repository’s context and can read its secrets. If a workflow then executes untrusted code from a fork, that code can compromise the pipeline or steal those secrets.

    GitHub’s docs describe the usual failure mode without requiring a novel attack write-up. Maintainers sometimes pick pull_request_target because they want fork pull requests to run CI and they want secrets (for example a private package registry). To test the contributor’s changes, they point checkout at the pull request’s head (or merge ref), or they fetch the fork some other way, and then they build or test whatever landed in the working directory. The workflow file is still the trusted copy from the default branch. The code that subsequently runs — a Makefile, npm install, a test script, a project hook, a dependency’s install step — can come from the fork.

    GitHub and the GitHub Security Lab call that class of bug a “pwn request.” The security guide notes that the same pattern is not unique to this one event: any secret-bearing workflow (issue_comment, workflow_run, and others) can recreate it if it downloads and runs untrusted pull-request code or treats artifacts from a fork’s workflow as trusted input. The December 2 default is a product-level attempt to make the highest-risk trigger opt-in for public repositories, not a claim that every other event is automatically safe.

    What the November brownouts will feel like

    Think of the brownouts as two scheduled two-hour rehearsals, not as the final outage. GitHub will temporarily enforce the default protection so you can see affected workflows before December 2.

    • During the window: pull_request_target attempts that the default rule would block, in affected public repositories, become failed runs with an error annotation. The workflows do not execute.
    • After the window: the default rule goes back to evaluate mode. Workflows can run again; insights and warnings remain the way to see what December 2 will permanently stop.
    • Private and internal repositories are not part of this drill.

    If your open-source project uses pull_request_target for something user-visible — a greeting comment, a preview deploy, a required status check — the brownout is when that automation silently (or noisily) disappears for two hours. Better to find that on November 9 than on December 2, when the change stops being temporary.

    How to prepare before November 9

    GitHub’s changelog points maintainers at Insights to see which workflow runs the rule would block, then offers two paths. The security guide says the same thing in slightly more operational language: while the policy is in evaluate mode, review policy insights and decide, for each affected workflow, whether pull_request_target is still required.

    1. If you do not need the privileged trigger, change the workflow to a safer event where appropriate — GitHub specifically names pull_request. That event covers the same pull-request activity, runs the workflow from the merge commit, and already applies the fork protections summarized above. If the job does not need extra secrets, this is the intended destination.
    2. If you must keep pull_request_target, create or update an applicable Actions event policy that explicitly allows it. The changelog says you can use workflow-file targeting so the allow list covers specific workflows rather than every privileged job in the organization.
    3. If you do not want to allow it, leave the default policy in place. After enforcement, GitHub will block workflows triggered by that event.

    We are not going to invent YAML for an Actions event policy here: GitHub documents policy configuration under its workflow-execution and Actions-policy pages, including a REST API for managing policies programmatically. If your organization already set an event policy, remember that the new default does not override it — you are already on a hand-written allow/deny path and should review that path rather than assuming December 2 will save you or break you automatically.

    A simple triage question, taken from GitHub’s own warning: only allow pull_request_target when it is necessary, and do not use that allow list as permission to check out, build, or run untrusted pull-request code with repository secrets or a privileged token.

    If you still need the privileged trigger

    Some workflows really do need elevated trust to respond to forks. GitHub’s examples include generating coverage that requires a private artifact registry, or producing authenticated checks against the incoming changes. The security guide asks you to work through two questions before you opt back in — and before you disable built-in checkout protections.

    • Can you use pull_request instead? If you do not need additional secret access, you probably can. More complex pipelines can be split so that anything which handles pull-request code runs without secrets, and anything which needs secrets never executes that code.
    • Is checked-out code ever executed? That is the flaw that turns a privileged workflow into a pwn request. Execution is broader than an obvious “build” step. Installers, test runners, generated scripts, and dependency install hooks can all run attacker-controlled code once the fork’s tree is in the working directory. GitHub’s guidance is that the checked-out pull request should be inspected as data and never executed.

    If you have worked through those questions and still need the trigger, GitHub documents an explicit, reviewable opt-out on actions/checkout: an input named allow-unsafe-pr-checkout, set to true, which allows checking out pull-request head refs from forks. The docs say the name is intentional — it should be easy to spot in code review and static analysis — and that you should enable it only after confirming the checked-out code is never executed. The protection covers fork pull-request refs handled by checkout; it does not cover fetching an unrelated third-party repository, using git fetch or gh pr checkout on your own, or running a downloaded artifact.

    That opt-out is a documented escape hatch for workflows that have already been designed not to execute untrusted code. It is not a reason to restore “run the contributor’s tests with our secrets” as a pattern.

    Hardening a privileged workflow

    GitHub lists controls that apply whether or not the job checks out pull-request code:

    • Restrict secrets and token permissions. Give GITHUB_TOKEN the least privilege it needs, and expose only the repository or organization secrets that job actually uses.
    • Understand the cache rules. To reduce cache poisoning, pull_request_target workflows have read-only access to the cache in the default branch’s scope: they can restore entries but cannot create or overwrite them. A save attempt fails with a warning; the rest of the job continues. If you need to populate the cache, GitHub says to do it from a trusted trigger such as push. A job can declare a write-capable cache-mode and opt out of the restriction — which, the docs warn, reintroduces the poisoning risk the restriction exists to prevent.
    • Isolate compute. If you use self-hosted runners, confirm the environment is restricted from internal resources and is not reused across Actions runs.
    • Treat other injection bugs as in-scope. Command injection from untrusted workflow inputs is a separate, well-documented class of Actions vulnerabilities. GitHub points teams at CodeQL for GitHub Actions and at the Security Lab’s writing on untrusted input.

    What this is — and what it is not

    ClaimStatusNotes
    Default block of pull_request_target in public repos on December 2, 2026Confirmed in GitHub’s Nov 2 changelogUnless an applicable Actions event policy allows the event
    Enforcement was previously scheduled for November 2ConfirmedDelayed
    Brownouts November 9 and 16, 16:00–18:00 UTCConfirmedFailed annotated runs; no execution; then back to evaluate mode
    Private, internal, and GitHub Enterprise Server repos are includedNoExplicitly excluded
    Evaluate mode already shows which runs would be blockedYesUse Insights / policy insights
    The trigger itself is being removed from ActionsNoIt remains available when a policy allows it
    Every pull_request_target workflow is already compromisedNoRisk appears when untrusted code is executed with secrets
    Switching to pull_request always preserves secret accessNopull_request from forks is intentionally secret-less and read-only by default

    FAQ

    Will my private repository’s workflows stop on November 9?

    Not because of this change. GitHub says private and internal repositories are not affected by the default rule or by the brownouts. The December 2 block is described for public repositories on GitHub Free, Team, and Enterprise Cloud.

    What should I do in the next 48 hours if I maintain a public repo?

    Search your workflows for pull_request_target, open policy insights / Insights to see which runs the default rule would block, and decide whether each job can move to pull_request or needs an explicit allow in an Actions event policy. The first brownout is November 9, 16:00–18:00 UTC.

    If a workflow fails during the brownout, is it broken forever?

    No. After each two-hour window the default rule returns to evaluate mode and those workflows can run again with warnings, until permanent enforcement on December 2.

    Is allowing the event in a policy enough to make a workflow safe?

    No. An allow policy only stops GitHub from blocking the trigger. Safety still depends on never executing untrusted pull-request code with secrets or a privileged token. GitHub’s warning on that point is explicit.

    Why not just always use pull_request_target so forks can run full CI?

    Because that is how the privileged context and the untrusted tree get combined. GitHub’s recommended default is pull_request whenever extra secrets are unnecessary. If you need secrets, split the work so secret-bearing jobs do not run contributor code.

    Does this replace adding secrets scanners or rotating leaked tokens?

    No. This is a workflow-execution default, not a secret-scanning product. Leaked credentials — including ones that land in git the way we described for Claude Code local settings files — still need rotation and history cleanup. Tightening CI triggers reduces one path attackers use against public repositories; it does not retire the others.


    Sources: GitHub Changelog — pull_request_target blocked by default December 2 (November 2, 2026); GitHub Docs — Securely using pull_request_target. Schedule, scope, and remediation options above are taken from those pages. We did not invent event-policy YAML or reproduce GitHub’s insecure example workflow.