The Pwn Request Reckoning: What Still Works Against GitHub Actions GitHub's 2026 platform changes to GitHub Actions make the default-case pull_request_target exploit significantly harder but do not eliminate the vulnerability class, according to a security research post updating a three-part GitHub Actions threat model. GitHub released actions/checkout@v7.0.0 on June 18, 2026, blocking fork code checkouts by default in untrusted triggers, added read-only cache tokens on June 26, 2026, backported fork checkout protections on July 20, 2026 to actions/checkout v2.8.0, v3.7.0, v4.4.0, v5.1.0 and v6.1.0 (v1 excluded), and reached GA on cache-mode on September 10, 2026 and Workflow Execution Protections on September 17, 2026. GitHub is scheduled on December 2, 2026 to enforce a default event policy blocking pull_request_target in public repositories without an explicit event policy, a rule in evaluate mode since September 17 that does not apply to private or internal repositories or to workflow_run; the researchers found that SHA-pinning actions/checkout to releases before the July 20, 2026 backport, such as @08eba0b resolving to v4.3.0, bypasses the protections entirely. For years, pull request target has been the canonical Pwn request vector: a workflow trigger that runs with repository secrets, yet can be triggered by anyone who opens a pull request from a fork. In 2026, GitHub responded with platform changes that make the default-case exploit significantly harder.. These changes represent real progress. Checkout protections, read-only cache tokens, and event policies close the paths that made exploitation trivial. But they don't eliminate the vulnerability class. They shift it. Attackers who previously exploited any pull request target workflow now need to find explicit opt-ins, outdated checkout versions, unprotected triggers, or script injection. In Part 1 https://www.wiz.io/blog/github-actions-security-threat-model-and-defenses of our GitHub Actions research, we laid out the threat model and core defenses, and Part 2 https://www.wiz.io/blog/github-actions-security-ai-powered-actions-vulnerabilities covered AI-powered actions. This post updates that threat model for 2026: what GitHub's changes actually protect against, where the gaps remain, and how defenders need to adjust. The audit checklist at the end covers what to look for in your own workflows. Recognizing the endemic risk posed by Pwn requests, GitHub spent 2026 systematically closing the gap through a phased rollout of platform-level protections and action updates. | Date | Milestone & Action Taken | |---|---| | June 18, 2026 | Release of actions/checkout@v7.0.0 mailto:actions/checkout@v7.0.0 , blocking fork code checkouts by default in untrusted triggers pull request target, and workflow run triggered by pull requests . | | June 26, 2026 | GitHub introduces read-only cache tokens at the platform level for untrusted triggers, preventing cache poisoning attacks. | | July 20, 2026 | Backported fork checkout protections across all active major versions of actions/checkout v2.8.0, v3.7.0, v4.4.0, v5.1.0, and v6.1.0; v1 excluded . Workflows referencing mutable version tags e.g., @v4 inherit these defenses automatically. | | September 10, 2026 | Fine-grained cache controls via cache-mode reached General Availability GA . | | September 17, 2026 | Workflow Execution Protections reached GA, enabling fine-grained event policies and actor rules. | | December 2, 2026 | Scheduled GitHub begins enforcing the default event policy that blocks pull request target in public repositories without an explicit event policy. The rule has been in evaluate mode since September 17. Private and internal repositories are not affected. | While this sequence of platform updates significantly strengthens default security configurations for GitHub Actions, they don't remove all risk. The December 2 enforcement is a default, not a ban. Maintainers whose automation depends on pull request target labelers, preview deploys, fork CI with secrets will add an event policy that allows it. Those are exactly the workflows that handle untrusted input with elevated privileges. The default policy also doesn't apply to private and internal repositories or to workflow run . The rest of this section covers how these surviving workflows can still be exploited. One of the most disconcerting findings in our research is how standard supply chain hardening advice https://www.wiz.io/blog/github-actions-security-guide - specifically pinning actions to exact commit SHAs - can inadvertently bypass GitHub's platform defenses. Because GitHub's backported protections rely on logic embedded within actions/checkout itself, pinning to SHA values prior to the July 20, 2026 backport release means the workflow runs legacy code without any safety checks. Our empirical testing across workflow triggers confirmed this discrepancy: referencing mutable tags like @v4 resolving to v4.4.x or pinned versions such as @v4.4.0 remain protected, whereas older versions like @v4.3.0 or SHA-pinned references to legacy releases such as @08eba0b... resolving to v4.3.0 offer no protection. To maintain protection, security teams using SHA pinning must ensure their refs are updated to match or exceed the minimum patched release versions: v2.8.0, v3.7.0, v4.4.0, v5.1.0, v6.1.0, or v7.0.0+. A second gap concerns workflows that bypass actions/checkout altogether. GitHub's protections are implemented within the action's code - any alternative method of fetching code operates unrestricted. Direct CLI invocations sidestep protections entirely: Third-party checkout actions implement their own git logic, so they don't inherit these protections. Any of them configured with a PR head ref will check out fork code unrestricted. GitHub's checkout protections only cover pull request target and workflow run : Pwn requests triggered in other event types besides pull request target such as issue comment will not be blocked by this change. Further hardening of additional events may be explored in future releases. GitHub changelog This creates an inconsistent security boundary: GitHub's cache controls explicitly treat https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching issue comment as a low-trust trigger, while checkout protections do not. Workflows using issue comment for bot commands /deploy , /test , /cherry-pick remain fully exploitable with checkout v7 - no allow-unsafe-pr-checkout flag required: Other privileged triggers have the same gap. repository dispatch also runs with secrets, and it's exploitable when a workflow uses attacker-influenced payload data to choose a checkout ref. Until GitHub extends checkout protections, these workflows have to enforce their own authorization, and it needs to hold from the moment the event fires until the code runs: - Verify who triggered it. For comment commands, check the commenter's actual repository permission getCollaboratorPermissionLevel , write or above . Don't rely on author association , which doesn't reflect current permissions. For repository dispatch , limit who holds a token that can send the event, and don't treat the payload as proof of who sent it. - Pin what was approved. refs/pull/N/merge is mutable, so an attacker can push a malicious commit after a maintainer comments /deploy. Check out the exact head SHA, and abort if the PR was updated after the comment was posted. - Treat the event payload as untrusted input. Validate comment arguments and dispatch payload fields against a strict, anchored allowlist regex, and pass them to the shell through environment variables, never through ${{ }} interpolation. A common misconception is that pull request target vulnerabilities require checking out fork code. In reality, attackers can achieve code execution without any checkout step, through script injection. When workflow authors interpolate event context directly into shell commands using ${{ }} expressions, GitHub substitutes the value into the script before the shell runs, so attacker-controlled data becomes part of the command itself: An attacker simply crafts a pull request with a malicious title: "; touch /tmp/pwned; echo INJECTED The quote closes the string, the semicolon ends the echo, and everything after it runs as a new command with the job's secrets and token. None of GitHub's 2026 changes touch this: there is no checkout to block, and the vulnerability lies in how the workflow handles untrusted input. The fix is to never interpolate untrusted input into a script. Pass it through an environment variable instead, so the shell treats it as data: The double quotes around $PR TITLE matter. Without them, the shell still word-splits and glob-expands the value. GitHub's read-only cache tokens protect the Actions cache service, but workflows can still exchange data through channels that remain unaffected. Artifact Poisoning The upload-artifact and download-artifact actions operate independently of cache tokens. The classic attack chain uses an unprivileged pull request workflow to upload attacker-controlled build outputs, then a privileged workflow run to download and execute them: This is exactly the workflow run scenario checkout v7 was built to block, and it doesn't help here. The privileged workflow never checks out fork code; it downloads it. Unlike cache entries, there's no platform equivalent that marks artifacts from untrusted runs as tainted, so any workflow that downloads and executes artifacts from a less-trusted run inherits the risk. Self-Hosted Runner State On non-ephemeral self-hosted runners, filesystem state persists between jobs. Local package manager caches ~/.npm, ~/.cache/pip , build directories, and installed tools live on the runner's disk, outside the Actions cache service, so read-only cache tokens don't cover them. Attacker code running under an untrusted trigger can write to these locations and poison the next trusted workflow scheduled on the same machine, including release and publish jobs. Use ephemeral runners, which are wiped after each job, for any workflow that untrusted events can trigger, and keep untrusted and trusted workflows in separate runner groups. Many security teams believe they have another safeguard in place: the "Require approval for all external contributors" setting under Settings - Actions - General. If enabled, fork PRs need maintainer approval before workflows run. Problem solved, right? Not quite. That setting only gates pull request workflows, which run the fork's own workflow YAML. For pull request target, GitHub considers the workflow definition trusted it comes from the base repository , so the approval setting doesn't apply and the run starts immediately. The irony cuts deep: pull request target is the more dangerous trigger secrets access, write tokens , yet it's the one that skips the approval requirement. If a pull request target workflow needs a human gate, put the privileged job behind an environment with required reviewers, or restrict who can trigger it with Workflow Execution Protections https://docs.github.com/en/actions/how-tos/administer/control-workflow-execution actor rules. Finally, developers who need to interact with fork code can explicitly disable checkout protections by enabling the allow-unsafe-pr-checkout flag: While the parameter name is deliberately alarming, determined development teams or third-party workflows may still employ it to maintain legacy automation, effectively reopening the exact same execution vector as before. Security teams should pay special attention to any use of this flag. To sum up, GitHub's 2026 security rollout deserves credit. Default event policies, checkout protections, and read-only cache tokens make the trivial Pwn request fork, PR, profit significantly harder. Starting December 2, pull request target will no longer run in public repositories unless an event policy explicitly allows it. Cache poisoning through the Actions cache is mitigated. These are real wins. But the vulnerability class isn't eliminated. It shifted. What remains exploitable: explicit opt-ins via allow-unsafe-pr-checkout , SHA-pinned versions predating the July 2026 backport, custom checkout scripts that bypass action-level controls, script injection requiring no checkout at all, unprotected triggers like issue comment and repository dispatch , artifact poisoning chains from pull request to workflow run , persistent state on non-ephemeral self-hosted runners, and private or internal repositories, which the default policy doesn't cover. The attack surface shrinks, but what remains is harder to spot. Start by auditing what you already run, then get ahead of the December 2 enforcement. Wiz Code https://www.wiz.io/platform/wiz-code automatically scans GitHub Actions workflows for Pwn requests, script injection, version gaps, and risky configurations to cover this residual attack surface. Alternatively, use open-source tools like zizmor https://github.com/zizmorcore/zizmor/ or even these basic grep searches to start the audit: In addition, run this script to resolve each SHA to its release tag, then compare against the patched versions: pull request target Enforcement Starting December 2, the default event policy will block pull request target in public repositories that have no explicit event policy. workflow run is not affected, and neither are private or internal repositories. Before that date: - Check policy insights to see which pull request target runs would be blocked. - Decide per workflow whether it actually needs pull request target. If not, move it to pull request . If a privileged follow-up step is still needed, a workflow run workflow can handle it, but it must treat the PR run's artifacts as untrusted data, never execute them. - For workflows that legitimately need fork access, create an explicit event policy and use workflow file targeting to allow pull request target only for those files. Treat every file on that allowlist as high-risk: run it through the audit above before adding it, and re-audit whenever it changes. State of SDLC Security 2026 https://www.wiz.io/reports/sdlc-security-report-2026