audit-actions
Installation
SKILL.md
Audit pull_request_target
What this skill catches
The pull_request_target + PR-head checkout combination is the entire bug class behind the public compromises of TanStack (May 2026), Nx (Aug 2025), PostHog (Nov 2025), Trivy (Feb 2026), tj-actions/changed-files (Mar 2025), and the prt-scan campaign (Mar 2026). Permission flags do not prevent it. SLSA provenance does not prevent it. Cache writes bypass permissions: contents: read entirely.
If a workflow uses pull_request_target AND checks out the PR head, attacker-controlled code runs on a runner that holds the base repo's GITHUB_TOKEN, has access to declared secrets, and can mint OIDC tokens for trusted publishing.
Run
- Find every usage. Locally:
grep -rn "pull_request_target" .github/workflows/. Org-wide:gh search code "pull_request_target" --owner $ORG --extension yml. - For each match, ask in order. Stop at the first "yes" — that's a finding.
- Does the workflow check out the PR head (
actions/checkoutwithref: ${{ github.event.pull_request.head.sha }}or similar)? CRITICAL. - Does it run any contributor-supplied code (
pnpm install,npm test,make build,actions/setup-*, a script committed in the PR)? CRITICAL. - Does it write to the Actions cache (no
lookup-only: trueonactions/cache)? HIGH. Cache writes use a runner-internal token and bypass workflow permissions; a poisoned cache is restored byrelease.ymllater. - Does it use third-party actions pinned by tag (
@v1,@main) rather than commit SHA? HIGH. - Does it set
id-token: write? HIGH in combination with any of the above — OIDC tokens are scraped from runner memory, not stolen from secrets. - Is the trigger even necessary? Most legitimate uses (labelling, commenting, metadata) work fine with
pull_request.
- Does the workflow check out the PR head (