
GitHub Actions Security Pt 1: Attacks & Defenses | Wiz Blog
Part one of a Wiz Research series building a threat model for GitHub Actions, covering three core risk classes: dangerous triggers like pull_request_target enabling "Pwn Request" attacks, script/expression injection via unsanitized workflow inputs, and compromised third-party actions in the supply chain. It walks through real incidents including the Trivy supply-chain compromise via a pull_request_target misconfiguration, the Ultralytics PyPI cryptominer injection via branch-name script injection, and the tj-actions/changed-files compromise that hit 22,000 repos targeting Coinbase, with corresponding defenses such as avoiding pull_request_target, binding/sanitizing inputs, and pinning actions to commit SHAs.
What it is
Part one of a Wiz Research two-part series on GitHub Actions security. The summary lists the three incidents; what it omits is the mechanism that makes each misconfiguration exploitable and the specific shape of the defenses. This document carries those.
How it works
The core distinction the summary doesn't give: pull_request runs the workflow from the PR head branch, but GitHub denies it secrets and grants read-only permissions — so attacker-modified workflow code is relatively contained. pull_request_target runs the workflow from the base branch (main), which GitHub treats as trusted, so it gets repository secrets and default write permissions with no org-level approval gate. The danger is the pattern below: trusted workflow code that checks out attacker-controlled PR head code and then executes it.
on:
pull_request_target:
types: [opened, synchronize]
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # checks out ATTACKER code
- uses: some-action@v1
with:
api-key: ${{ secrets.API_KEY }} # exposed to attacker
- run: make build # runs checked-out code- Trivy: attacker replaced the internally-authored
setup-goaction code in the checked-out fork, gaining execution and stealing the org-level token. - Ultralytics:
${{ github.head_ref }}/${{ github.ref }}(the PR branch name) was injected directly into arunblock unsanitized. The page notes the${IFS}shell trick as a WAF-bypass now appearing in CI/CD payloads.
pull_request_target is not the only dangerous trigger — seven others share its properties (triggerable without write permission, run in main's context with secrets/write). workflow_run is called out specifically: it consumes upstream workflow artifacts, so poisoning a parent workflow poisons the downstream one.
What to do
- Prefer avoiding
pull_request_target. If required: disable forking, gate the run on manual review, and never execute arbitrary commands on checked-out code. The page states none of these are bulletproof. - Against script injection: bind untrusted inputs to environment variables and reference them with quoted shell syntax (
"$MY_VAR") so the shell treats content as a literal; where even quoting is insufficient, sanitize against an allow-list regex (e.g. alphanumerics and hyphens only). - Against compromised third-party actions: pin actions to full commit SHAs.
Caveats
- The
pull_requestapproval gate is bypassable — attackers can promote themselves to "first-time contributor" via a trivial syntactic fix (demonstrated in a Praetorian PyTorch compromise). - SHA pinning "may not be effective for reusable workflows and nested actions."
- Credential compromise is deliberately excluded from this threat model; AI-powered action risks are deferred to Part 2.
Organisations named here
- Praetorian
- XMRig
Technologies named here
- tj-actions/changed-files
- actions/checkout
- setup-go
- ultralytics/actions
- Ultralytics PyPI releases
- SDLC Infrastructure Threat Framework
- Trivy
- PyTorch
- GitHub Actions
- PyPI
- Ultralytics
- Coinbase
Techniques named here
- Pwn Request
- pull_request_target misconfiguration
- Script injection / expression injection
- Other dangerous triggers
- Compromised 3rd-party actions / supply chain compromise
- Bypassing fork PR approval gate
Threat actors named here
- tj-actions compromise attacker
- Ultralytics supply chain attacker
- Trivy supply chain attacker
- PyTorch compromise researchers
Related in DevSecOps
JFrog: The Governance Gap Between Your Policy and Your Pipeline

Dev Machine Guard Now Supports Windows - StepSecurity

Socket: TanStack npm Packages Compromised
