RSTR-GHA-001 — pull_request_target + PR-head checkout
Summary
A GitHub Actions workflow triggers on pull_request_target and
checks out the pull-request head (ref: ${{ github.event.pull_request.head.sha }}).
pull_request_target runs with full repo-secret access — by design,
so workflows can post comments — but combining it with a PR-head
checkout means an attacker-authored PR runs with the secrets,
yielding straightforward exfiltration via curl, env-dump, or any
run: step.
This is the most commonly exploited GHA misconfiguration class.
Severity
Critical.
Languages
GitHub Actions workflow YAML (.github/workflows/*.yml).
What rastray flags
on:
pull_request_target: # ← flagged combo
types: [opened, synchronize]
jobs:
build:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
What rastray deliberately does not flag
on: pull_request— that trigger runs without secrets, so PR-head checkout is safe.on: pull_request_targetwithout any PR-head checkout — useful and safe; the workflow operates onmaincontent.
How to fix it
Pick one of these patterns depending on what the workflow needs:
Pattern A — read-only checks (lint, test, build the PR's code):
use on: pull_request. No secrets, PR head is checked out:
on: pull_request
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cargo test
Pattern B — labelling/commenting on the PR (needs secrets, must
not run untrusted code): use pull_request_target and do not
check out the PR head:
on: pull_request_target
jobs:
label:
permissions: { pull-requests: write }
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # checks out base, NOT PR head
- run: ./scripts/label.sh
Pattern C — both needed: split into two workflows. One on
pull_request does the build; one on pull_request_target reads the
build artefact and posts a comment.