# Stealing arbitrary GitHub Actions secrets

GitHub allowed PR base ref to be set to a commit hash via edit, so pull_request_target workflows ran attacker code with repo secrets.

- Payout: $25,000
- Severity: critical
- Program: GitHub
- Credited: Teddy Katz
- Disclosed: 2021-03-17
- CVE: CVE-2021-22862
- Write-up quality: 9/10
- Original: https://blog.teddykatz.com/2021/03/17/github-actions-write-access.html
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-teddykatz-com-2021-03-17-github-actions-write-access-html
- Tags: domain:web impact:integrity kind:bounty platform:blog sev:critical tech:github-actions technique:incomplete-fix technique:source-review vuln:access-control vuln:auth-bypass

**Target:** GitHub pull request base ref / Actions pull_request_target
**Root cause:** Base ref validation applied only on PR creation, not on edit, so baseRefName could be set to a commit hash or attacker-modifiable symbolic ref. pull_request_target trusted the base ref as a protected branch and ran workflows with secrets.
**Steps:**
1. Create PR with valid base branch via GraphQL createPullRequest
2. Edit PR baseRefName to a commit hash `fd9cfdc590e789ae559b5a7878e7e6b929a249d9` (or shorthash / `refs/pull/5/head`)
3. Commit a malicious workflow with `on: pull_request_target` to the fork
4. Set PR base ref to that commit hash
5. Workflow runs with victim repo secrets and GITHUB_TOKEN
**How found:** Tried setting baseRefName to a commit hash; creation rejected but edit succeeded, revealing validation only on creation. Then reasoned that pull_request_target trusts the base ref as protected, but commit hashes are shared from forks and attacker-controllable.
**Exploitation:** Attacker forks a public repo using Actions, opens a PR, commits a malicious pull_request_target workflow to the fork, then edits the PR base ref to that commit hash. The trusted workflow executes with the base repo's secrets, granting GITHUB_TOKEN write access and any stored credentials (e.g. package manager publish tokens), enabling supply-chain compromise.
**Escalation:** Could be applied across many open-source projects at once to steal package manager credentials and publish malicious package updates, a larger-scale eslint-scope-style supply chain attack.
**Insight:** When a field is validated on create but not update, test the update path with semantically invalid values. Then check what downstream trust assumptions depend on that field's validity (here, CI treating base ref as a protected branch).
