T-38-SEC-PWN: review-bot pwn-request mitigation
Finding
CodeQL (actions/checkout-of-untrusted-code, "Checkout of untrusted code in a
privileged context") flagged .github/workflows/review-bot.yml on PR #17.
The review job runs on pull_request_target, which mints a GitHub App
installation token with pull-requests: write scope before the diff step
ran. The prior "Compute PR diff (base...head)" step fetched the PR head ref
directly (git fetch origin pull/<n>/head:pr-head) into the runner's local
git object database and then diffed against it. Fetching attacker-controlled
ref content into a privileged job's git state is the classic GitHub Actions
pwn-request pattern (see GitHub's own docs on "Preventing pwn requests"),
even though the original step never wrote that content to the working tree
or executed it directly.
Mitigation
The privileged review job is now checkout-free of any untrusted ref:
- The eligibility classifier (
.github/scripts/classify-automerge-eligibility.ps1) already sourced its input exclusively fromgh pr view --json files,author(API text), not from any checked-out ref. - The diff step now calls
gh pr diff <n> --repo <repo>(GitHub API over HTTPS, returning diff text) and streams that text directly intocritic_cliover stdin (--diff -). Nogit fetch/git checkoutof the PR head, and no PR-head commit ever enters the runner's git object database or filesystem. - The only
actions/checkoutcalls remaining in the job are: (1) the job's own repository at its default/base ref (never the PR head — noref:override is supplied, so underpull_request_targetthis resolves to the base branch), and (2)Coding-Autopilot-System/autogenpinned to a fixed, trusted commit SHA forcritic_cli. Neither checks out attacker-controlled content. - Added fail-closed handling: if
gh pr diffitself fails (non-zero exit), the job now hard-stops rather than silently treating an empty/partial diff as "no findings" and proceeding toward approval.
Verification
- Structural check:
grepconfirms zero occurrences ofgit fetch .*pull/,pr-head, oractions/checkoutwith a PR-headref:in.github/workflows/review-bot.yml. The remainingactions/checkoutuses are the base-ref self-checkout and the pinned trustedautogencheckout. - The change was pushed to PR #17 (
feat/merge-flow-review-bot); GitHub's CodeQL check re-runs automatically onsynchronizeand is expected to clear the "Checkout of untrusted code in a privileged context" alert on the updated lines.
Note on scope
This note was added directly to PR #17 rather than to PR #18, because PR #18 ("fix(release): resolve reusable workflow reference") is an unrelated release-engineering fix and does not contain a merge-flow threat table to update.