# pull_request_target fork code execution

Privileged workflow that checks out or runs untrusted PR head code, exposing secrets and write tokens

_Area: Software supply chain and CI/CD. Seen in 5 disclosed reports; 4 confirmed bounties, median $7,500, range $500-$25,000; latest 2026-03-11. Updated 2026-10-23._

## How it works
`pull_request_target` runs in the base repository's context: it gets the base repo's secrets and a write-scoped `GITHUB_TOKEN`. That is safe only if the workflow never touches the fork's code. The assumption that breaks is that the trigger alone makes the run trusted. If the workflow then checks out the PR head (or a ref/SHA derived from PR data) and runs a build, install, or script, attacker-controlled files execute with the base repo's privileges. The trust boundary is the checkout, not the trigger. The same leak occurs when a CI system runs untrusted fork code with base-repo credentials attached [E1](https://bugbountylibrary.com/r/blog%3Ablog-tyage-net-posts-2021-04-02-improper-access-control-github-workflow.md).

## Where it shows up
- `pull_request_target` (or `issue_comment`) combined with any checkout of `github.event.pull_request.head.*`, `head.sha`, or a PR number passed to `gh pr checkout` [E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package.md)[E7](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-04-15-an-obscure-actions-workflow-vulnerability-in-googles-flank.md).
- Package-manager steps that execute repo files: `setup-node` with `cache:`, `npm`/`yarn` hooks, `mvn` on a PR `pom.xml`, `make build` on a PR Makefile [E2](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md)[E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package.md)[E8](https://bugbountylibrary.com/r/blog%3Alf-lc-vrp-175896812.md).
- Actor guards like `if: github.actor == 'dependabot[bot]'` treated as a safety control [E2](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md).
- Values parsed from PR/issue data flowing into `run:` steps [E7](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-04-15-an-obscure-actions-workflow-vulnerability-in-googles-flank.md).
- Cloud build configs (CodeBuild/CloudBuild/Azure DevOps) that auto-run fork PRs with an attached IAM/service role [E5](https://bugbountylibrary.com/r/blog%3Adivyanshu-mehta-gitbook-io-researchs-hijacking-cloud-ci-cd-systems-for-fun-and-profit.md).

## How to review
Find every privileged trigger and trace what code and data reach execution. The invariant: no file, ref, or value originating from the fork may be checked out, built, or interpolated into a shell in a run that holds secrets or a write token. Safe shapes split into two jobs: an unprivileged job builds the PR, a separate privileged job consumes only artifacts, with no secret exposure to the first. Confirm the checkout ref is the base branch, not PR head. Treat actor guards as convenience, not security: a fork can trigger events that satisfy them [E2](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md). A PR need not be merged; the workflow run itself executes fork code [E3](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-m-red-team-asyncapi-supply-chain-compromise-via-github-actions.md).

## Variants seen
- Dependabot actor-confusion: guard bypassed via a synchronize event, then cache step executes PR `package.json` [E2](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md).
- Direct fork head checkout plus `make build` [E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package.md); formatter action running `mvn` on PR `pom.xml` [E8](https://bugbountylibrary.com/r/blog%3Alf-lc-vrp-175896812.md).
- `issue_comment` deriving a PR number into `gh pr checkout` [E7](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-04-15-an-obscure-actions-workflow-vulnerability-in-googles-flank.md).
- Cloud build systems running fork PRs with reachable instance metadata, exposing role credentials [E5](https://bugbountylibrary.com/r/blog%3Adivyanshu-mehta-gitbook-io-researchs-hijacking-cloud-ci-cd-systems-for-fun-and-profit.md).
- Adjacent: base-ref resolution bug letting a closed PR reopen against attacker code [E2](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md).
- Broader sink class: injection into CI-executed files (test configs, build scripts, npm hooks) across many repos [E7](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-04-15-an-obscure-actions-workflow-vulnerability-in-googles-flank.md).

## Why fixes fail
A proposed fix splitting the workflow into two jobs sat unmerged for 58 days while the flaw stayed live [E3](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-m-red-team-asyncapi-supply-chain-compromise-via-github-actions.md)[E6](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-asyncapi-npm-packages-backdoored-via-github-actions.md).

## Impact and severity
Secret and token theft leading to repo pushes, cloud credential exposure, and backdoored npm packages reaching downstream users [E3](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-m-red-team-asyncapi-supply-chain-compromise-via-github-actions.md)[E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package.md)[E6](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-asyncapi-npm-packages-backdoored-via-github-actions.md)[E7](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-04-15-an-obscure-actions-workflow-vulnerability-in-googles-flank.md). Severity is high: write tokens and publish credentials are directly reachable, and blast radius grows with downstream tag-pinned consumers, who stayed exposed after an upstream action was retagged [E2](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Ablog-tyage-net-posts-2021-04-02-improper-access-control-github-workflow.md
- E2: https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-11-11-release-drafter-to-google-accompanist-compromise-vrp-writeup.md
- E3: https://bugbountylibrary.com/r/blog%3Awiz-io-blog-m-red-team-asyncapi-supply-chain-compromise-via-github-actions.md
- E4: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package.md
- E5: https://bugbountylibrary.com/r/blog%3Adivyanshu-mehta-gitbook-io-researchs-hijacking-cloud-ci-cd-systems-for-fun-and-profit.md
- E6: https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-asyncapi-npm-packages-backdoored-via-github-actions.md
- E7: https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2024-04-15-an-obscure-actions-workflow-vulnerability-in-googles-flank.md
- E8: https://bugbountylibrary.com/r/blog%3Alf-lc-vrp-175896812.md
