GitHub Actions Adds an Admission Gate; pull_request_target Still Needs a Trust Boundary
📌 Key Takeaways
- Admission Control vs Runtime Sandbox: GitHub Actions workflow execution protections (GA September 17, 2026) enforce actor, event, and file-targeted allowlists before runner startup, but do not sanitize untrusted code once a job begins execution.
- The pull_request_target Threat Surface: Workflows triggered by
pull_request_targetrun in the context of the base branch with access to repository secrets; checking out and executing untrusted fork PR code remains a critical vulnerability path. - November 2, 2026 Rollout Scope: GitHub's planned default block targets public repositories without existing event policies, leaving private/internal repositories and explicitly configured workflows under customer governance.
GitHub made workflow execution protections generally available on September 17, 2026. The feature lets administrators decide which actors and events may start a GitHub Actions workflow before a runner begins executing the repository’s YAML. General availability also added workflow-file targeting, policy Insights, and REST API management.
A second change arrives on November 2, 2026, when GitHub plans to enforce a default block on pull_request_target for a defined group of public repositories. The rollout is not a universal shutdown: it excludes private and internal repositories, does not replace an applicable event policy, and has an additional pre-GA eligibility condition.
The security boundary is equally important. Workflow execution protections can reject a run before startup, but they do not inspect every command or remove privileges from an admitted job. A permitted pull_request_target workflow can still expose tokens or secrets if it later executes contributor-controlled code.
The policy decides whether a run may start
GitHub describes workflow execution protections as an allowlist evaluated before workflow execution:
- Actor rules determine who may trigger a workflow. Supported categories include individual users, repository roles, GitHub Apps, Copilot, and Dependabot.
- Event rules determine which events are permitted, including
push,pull_request,pull_request_target, andworkflow_dispatch. - Workflow targeting can limit a policy to selected workflow files instead of applying one rule to every workflow in a repository.
- Policy Insights show runs blocked by active policies and runs that would be blocked by policies in evaluate mode.
- REST endpoints support creating, reading, updating, and deleting Actions policies at repository, organization, and enterprise scopes.
These capabilities are documented in the September 17 GA announcement, the current workflow-execution configuration guide, and the Actions policies REST API.
The practical interpretation is that execution policy is an admission control, not a workflow sandbox. It can reject a disallowed actor-event-workflow combination before execution. Once admitted, the workflow still follows its configured jobs, permissions, secrets, actions, commands, caches, artifacts, and runner environment.
Illustrative, not a measured benchmark: the policy gate evaluates actor, event, and workflow path before startup. The separate post-admission boundary is crossed when a privileged job turns contributor-controlled content from data into executable input.
November 2 affects a specific public-repository population
GitHub’s rollout has four confirmed conditions:
- The default policy concerns the
pull_request_targetevent. - GitHub adds it to public repositories that do not already have an applicable Actions event policy.
- The automatic default does not apply to private or internal repositories.
- Automatic enforcement on November 2, 2026 applies to affected repositories that were using GitHub’s default
pull_request_targetpolicy before general availability.
Until enforcement, the default rule runs in evaluate mode, allowing administrators to inspect affected runs through policy Insights without blocking them. GitHub documents two choices for an affected workflow:
- Leave the default rule in place, causing
pull_request_targetruns to be blocked after enforcement. - Create or update an applicable event policy that explicitly permits
pull_request_target.
Workflow-file targeting allows that permission to be limited to specified workflows rather than reopening the event for an entire repository. The precise rollout conditions and administrator choices appear in both the GA announcement and GitHub’s pull_request_target security guide.
Illustrative rollout map: only qualifying public repositories enter GitHub’s default evaluate-to-enforcement path. Existing applicable event policies and private or internal visibility place a repository outside that automatic path.
Administrators should therefore inspect the policy actually applied to each repository. An unchanged workflow may stop running because a higher-level Actions policy changed, while a private repository receives no automatic pull_request_target block from this rollout.
Why pull_request_target is privileged—and safe only under a narrow condition
A pull_request_target workflow runs with elevated trust. According to GitHub’s security documentation, the workflow receives the base repository’s GITHUB_TOKEN and can access repository and organization secrets made available to the job.
The event changes where trusted workflow content comes from:
- A fork-originated
pull_requestworkflow uses the pull request’s merge context. GitHub limits it to a read-onlyGITHUB_TOKEN, withholds other secrets, and applies fork-approval protections. - A
pull_request_targetworkflow and a defaultactions/checkoutcall use the base repository’s default branch rather than the fork’s branch. - No fork code is executed by default in that privileged context.
That default is what makes pull_request_target suitable for narrowly scoped operations such as labeling, triage, or authenticated status updates. The unsafe transition occurs when the workflow overrides the default, retrieves contributor-controlled content, and then executes it.
Checkout alone is not necessarily the final exploit step. The vulnerability is completed when a later operation builds, tests, imports, sources, installs, or otherwise runs material controlled by the pull request. Examples include:
- A pull-request-controlled
Makefilereached bymake test - Package lifecycle hooks invoked by
npm install - Modified build scripts or test files
- Dependencies or configuration that influence code execution
- A downloaded binary or script carried through a workflow artifact
GitHub Security Lab calls the combination of a privileged trigger, explicit untrusted checkout, and subsequent execution a pwn request. Its documented examples show that malicious behavior can be embedded in ordinary build and dependency mechanisms rather than an obvious standalone attack script.
Built-in checkout safeguards do not cover every acquisition path
GitHub has also hardened actions/checkout. The current safeguard refuses common attempts to fetch fork pull-request head or merge commits from pull_request_target workflows and certain workflow_run workflows.
That protection is deliberately narrower than the overall vulnerability class. GitHub’s checkout security announcement and pull_request_target guide identify routes outside the protected pattern, including:
- Fetching a head reference with
git - Using
gh pr checkout - Downloading an artifact produced from untrusted pull-request content
- Checking out an unrelated untrusted repository
- Recreating the same pattern under another privileged event, such as
issue_comment
The same rule applies to workflow_run: artifacts from an unprivileged workflow remain untrusted. Passing a binary or script through an artifact boundary does not make it safe to execute in a later job with secrets or write permissions.
The security property is therefore not “checkout was blocked” or “the workflow uses two jobs.” It is: untrusted content must not gain executable influence in a privileged context.
Post-admission controls still matter
GitHub’s hardening guidance retains several controls after a workflow passes the policy gate.
Minimize credentials
Set the GITHUB_TOKEN to the least privileges the workflow needs and expose only necessary repository or organization secrets. A narrowly admitted workflow with excessive credentials still has an unnecessarily large failure radius.
Preserve cache restrictions
GitHub documents read-only access to the default branch’s cache scope for pull_request_target workflows. These jobs can restore existing entries but cannot create or overwrite them unless a workflow explicitly opts into write-capable cache behavior. Enabling cache writes for this privileged event reintroduces the cache-poisoning risk the restriction is intended to reduce.
Treat artifacts as untrusted input
A privileged follow-up workflow may consume a small result produced by untrusted computation, but it should parse and validate that result as data. It should not run transferred executables, source scripts, import untrusted modules, or unpack content into a location where tooling may execute it automatically.
Isolate runner infrastructure
GitHub advises that self-hosted runners used for this class of workflow be isolated from internal resources and not reused across runs. An ephemeral runner reduces persistence between jobs; network isolation limits what compromised code can reach.
These controls are complementary. Actor and event rules constrain admission, token settings constrain authority, data validation constrains influence, and runner isolation constrains impact.
Separate contribution testing from authenticated automation
For code that must be compiled, installed, built, or tested, GitHub recommends pull_request when additional secret access is unnecessary. That event is designed to run fork-controlled code with restricted credentials.
When a process needs both untrusted computation and a later authenticated action, GitHub Security Lab documents a two-workflow structure:
- An unprivileged
pull_requestworkflow executes contributor code without sensitive credentials. - It emits a minimal result as an artifact.
- A privileged
workflow_runworkflow reads that result and performs a narrow authenticated operation. - The privileged workflow continues to treat the artifact as untrusted data.
Schema validation, strict value allowlists, bounded file sizes, and rejection of unexpected files are prudent implementation choices for that boundary. They are design recommendations, not evidence that GitHub automatically validates artifact semantics.
Workflow-path policy can reinforce the architecture from outside the YAML:
| Workflow purpose | Appropriate execution context | Policy posture |
|---|---|---|
| Build, test, lint, or scan fork code | Unprivileged pull_request |
Permit contributor execution without secrets |
| Labeling or narrowly scoped PR metadata work | Carefully hardened pull_request_target |
Allow only the required workflow path and actors |
| Release or deployment | Trusted events and designated actors | Apply the narrowest actor, event, and workflow-path rules |
Illustrative policy architecture: contributor CI, privileged pull-request metadata automation, and deployment workflows receive different admission rules because they operate at different trust levels.
REST states and the evaluate-mode entitlement
The Actions policies REST API defines three enforcement values:
disabledactiveevaluate
It also states that evaluate is available only with GitHub Enterprise. The current configuration guide is more specific in the user interface, labeling Evaluate as GitHub Enterprise Cloud only.
The API supports workflow_path conditions with include and exclude arrays. At organization scope, a policy condition targets repositories by name, ID, or repository property and may also contain a workflow-path condition. Omitting workflow_path targets all workflows covered by that policy operation.
The September 17 announcement says workflow execution protections are generally available at enterprise, organization, and repository levels, but that statement should not be read as a complete plan-entitlement matrix. GitHub’s current configuration documentation says the feature is available for all public repositories and for private repositories on GitHub Team or GitHub Enterprise; evaluate mode has the narrower Enterprise Cloud limitation.
Release status and current documentation
As of September 20, 2026, GitHub’s September 17 release announcement records workflow execution protections as generally available. The current Actions policy concept page and configuration guide describe the active capabilities and the November 2 policy path.
GitHub has consolidated older organization-scoped URLs into its current documentation. For release status, use the dated changelog; for plan support and configuration behavior, use the current top-level documentation and confirm the controls visible in the relevant account.
Migration decision
Before November 2, review policy Insights and trace every privileged workflow past its trigger:
- Identify workflows using
pull_request_target,workflow_run, or privilegedissue_commentautomation. - Record their token permissions, available secrets, cache behavior, artifact inputs, and runner type.
- Trace whether contributor-controlled code or artifacts are fetched by any mechanism.
- Determine whether a later step can execute or give control to that content.
- Move contributor-code execution to
pull_requestwhenever secrets are unnecessary. - Retain privileged triggers only for narrow authenticated tasks that keep untrusted content as data.
- Apply actor, event, and workflow-path policy to enforce those boundaries before execution.
Decision rule: If a job must execute contributor-controlled code, run it without privileged credentials. If a job must hold privileged credentials, do not let contributor-controlled content influence execution.
Proposed validation checks
The following checks are proposed; they are not measured Tech Trend Insight results:
- In a disposable public repository without production secrets, compare the same event under evaluate and active policy states.
- Confirm that workflow-path include and exclude patterns affect only the intended workflow files.
- Pass a small inert result between unprivileged and privileged workflows, then verify that unexpected files, fields, types, and values are rejected.
- Test self-hosted-runner isolation only on disposable infrastructure disconnected from production networks, signing systems, registries, and credentials.
Official Sources
- workflow-execution configuration guide
- Actions policies REST API
- pull_request_target security guide
- GitHub’s security documentation
- documented examples
- Actions policy concept page
Frequently Asked Questions (FAQ)
Why is pull_request_target considered one of GitHub Actions’ highest-risk triggers?
Unlike standard pull_request events, pull_request_target workflows execute in the context of the repository's base branch and can access secrets or token permissions that the workflow and repository configuration make available. If the workflow checks out the contributor’s PR head ref and runs build scripts (for example, npm test), untrusted code can steal available secrets or backdoor release artifacts.
Do GitHub's new execution protections prevent script injection vulnerabilities?
No. Workflow execution protections operate exclusively as an admission gate—evaluating whether an actor or event is permitted to start a job. Once admitted, the runner executes the YAML workflow steps as authored. If a step interpolates untrusted user input directly into inline bash scripts or runs unreviewed code, script injection remains fully exploitable.
What will happen to public open-source repositories on November 2, 2026?
GitHub plans to automatically enforce a default block on pull_request_target for public repositories that do not already have an explicitly configured event policy. To prevent breakage of legitimate CI automation, repository maintainers should evaluate their workflows using policy Insights and configure targeted file allowlists before the November cutoff.
What is the recommended architecture for running tests on untrusted pull requests?
Security engineering best practice separates workflows into two distinct phases: run untrusted tests and builds under an unprivileged pull_request event (without access to secrets), and upload test artifacts. A separate, privileged workflow then consumes and reviews the generated artifacts without re-executing contributor-controlled scripts.