# Self-hosted runners on fork PRs

Public repo workflows running untrusted fork PR code on persistent self-hosted runners

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

## How it works
A public repository attaches a self-hosted runner to workflows triggered by `pull_request`. Fork PR code is untrusted, but the runner is not ephemeral: it keeps state between jobs and often holds secrets, tokens, or cloud credentials. The assumption that breaks is that only trusted code reaches the runner. In practice anyone who becomes a "previous contributor" (even via a one-character typo PR) can get their fork PR workflow to execute without approval, and that code runs on the same persistent machine that later trusted jobs use [E1](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md)[E2](https://bugbountylibrary.com/r/blog%3Ajohnstawinski-com-2024-01-11-playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch.md).

## Where it shows up
- Workflows with `pull_request` triggers and `runs-on: self-hosted` in a public repo [E1](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md)[E2](https://bugbountylibrary.com/r/blog%3Ajohnstawinski-com-2024-01-11-playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch.md).
- Fork-PR approval limited to "first-time contributors" rather than all outside contributors [E1](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md)[E2](https://bugbountylibrary.com/r/blog%3Ajohnstawinski-com-2024-01-11-playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch.md).
- Checkout logs containing "Cleaning the repository" and repeated runner names, indicating non-ephemeral runners [E1](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md).
- Workflows that register a runner, then poll/sleep before dispatching a job, leaving a window where untrusted code runs before cleanup steps [E3](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-github-actions-staff-access-token-en.md).
- Secrets or PATs passed to steps that execute after an untrusted job on the same runner [E3](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-github-actions-staff-access-token-en.md).

## How to review
The invariant: no code from an untrusted fork may execute on a runner that is reused or that holds secrets. Check that fork-PR workflows either require approval for all outside contributors or run only on ephemeral, secret-free runners. Trace every secret and token to the step that consumes it and confirm no untrusted job runs earlier on that runner. Treat any persistent runner attached to a public repo as compromised by design.

## Variants seen
- Persistent runner on a public repo with default fork-PR approval, allowing persistence and secret/token theft [E1](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md).
- Prior-contributor fork PRs running without approval, enabling rogue runner install and PAT/AWS key theft to backdoor releases [E2](https://bugbountylibrary.com/r/blog%3Ajohnstawinski-com-2024-01-11-playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch.md).
- Runner registered inside a workflow, with a race window before the cleanup step, letting a malicious PR steal a staff PAT [E3](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-github-actions-staff-access-token-en.md).

## Impact and severity
High: stolen GITHUB_TOKEN, PATs, and AWS keys, and in one case a path to backdoor releases [E1](https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md)[E2](https://bugbountylibrary.com/r/blog%3Ajohnstawinski-com-2024-01-11-playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch.md)[E3](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-github-actions-staff-access-token-en.md). Severity rises with persistent runners, broad token scopes, and release-signing or cloud credentials reachable from the runner.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aadnanthekhan-com-2023-12-20-one-supply-chain-attack-to-rule-them-all.md
- E2: https://bugbountylibrary.com/r/blog%3Ajohnstawinski-com-2024-01-11-playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch.md
- E3: https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-github-actions-staff-access-token-en.md
