workflow-run-deploy-gate-fork-pr-ref-name-escalation

Detects and fixes fork-PR privilege escalation in workflow_run deploy gates on GitHub Actions.

3|Updated May 8, 2026
One-click install
npx skills add https://github.com/wan-huiyan/agent-traffic-control --skill workflow-run-deploy-gate-fork-pr-ref-name-escalation-wan-huiyan
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: workflow-run-deploy-gate-fork-pr-ref-name-escalation
Source: https://github.com/wan-huiyan/agent-traffic-control/tree/main/plugins/agent-traffic-control/skills/workflow-run-deploy-gate-fork-pr-ref-name-escalation
Command: npx skills add https://github.com/wan-huiyan/agent-traffic-control --skill workflow-run-deploy-gate-fork-pr-ref-name-escalation-wan-huiyan

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? A GitHub Actions deploy job triggered by on: workflow_run and gated only on head_branch == 'main' and conclusion == 'success' can be exploited by a fork PR: a fork's default branch is also named main, so a fork's CI run can satisfy the gate and cause the privileged upstream deploy job to ship attacker-controlled code to production via OIDC/WIF credentials. ## Core Features & Use Cases - Vulnerability Detection: Identifies workflow_run-triggered privileged jobs (deploy, publish, release, cloud infra apply) whose if: condition trusts only the unqualified ref name and conclusion. - Concrete Fix Pattern: Adds origin checks — workflow_run.event == 'push' and workflow_run.head_repository.full_name == github.repository — so only CI runs from pushes on your own repo can trigger the deploy. - Verification Guidance: Explains how to confirm a fork-PR CI run leaves the deploy job skipped while a real merge-to-main run executes the gated path. - Use Case: While reviewing a CI-gated auto-deploy-on-merge workflow that mints cloud credentials with id-token: write, apply this Skill to close the fork-PR escalation path before merge. ## Quick Start Review my GitHub Actions workflow that deploys after CI passes on main and check whether the workflow_run gate is exploitable by a fork PR.

Frequently Asked Questions about workflow-run-deploy-gate-fork-pr-ref-name-escalation

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I securely gate a GitHub Actions deploy on workflow_run?▼

Gate on the triggering run's origin, not just its branch name: require workflow_run.event == 'push' and workflow_run.head_repository.full_name == github.repository in addition to conclusion == 'success' and head_branch == 'main'. This ensures only CI runs from pushes on your own repo trigger the deploy.

Why is head_branch == 'main' unsafe in a workflow_run deploy gate?▼

head_branch is the unqualified ref name, and a fork's default branch is also named main. A fork PR's CI run can complete successfully with head_branch == 'main', causing the privileged upstream workflow_run deploy job to build and ship the attacker's head_sha.

Can a fork PR access secrets or OIDC in GitHub Actions?▼

The fork's CI job on pull_request cannot access secrets or OIDC, but the deploy is a separate workflow_run job that always runs in the privileged upstream context regardless of the triggering run's origin. That separation is what makes the gate exploitable.

Is this workflow_run exploit possible on a private repository?▼

On a private repo the attack is unreachable today because forks cannot run CI without write access. The one-line fix is still recommended because it future-proofs the workflow against a private-to-public visibility flip.

How do I verify the workflow_run deploy gate actually works?▼

Confirm a fork PR or pull_request CI run leaves the deploy job skipped, while a real merge to main with a successful push-event CI run creates the workflow_run run and executes the deploy. A dispatch or cancelled-run success does not prove the gated path works.

Does this apply to jobs other than deploys?▼

Yes, any privileged workflow_run-triggered job is affected, including publish, release, signing, image push, and infrastructure apply with cloud CLIs. The same origin checks on event and head_repository apply to all of them.