
The complete GitHub Actions security checklist
A detailed 33-point checklist for hardening GitHub Actions workflows, covering trigger risks (pull_request_target, workflow_run), script/prompt injection into run: steps and AI agent prompts, mutable action/package references, artifact handling, secrets scoping, OIDC over static cloud credentials, runner isolation, and token/org-level permission defaults. Each section is backed by real-world incidents (Trivy tag hijack, tj-actions/changed-files compromise, Ultralytics PyPI attack, Nx/s1ngularity, Shai-Hulud, TanStack npm trusted-publisher abuse, PyTorch self-hosted runner takeover), making it a practical reference for securing CI/CD pipelines against the supply-chain attacks that have hit open source in 2025–2026.
What it is
Aikido's GitHub Actions security checklist, focused on the trigger-configuration attack surface that has driven recent CI/CD supply-chain incidents. The fetched text covers the "start here" top-five priorities plus two detailed sections: pull_request_target (pwn requests) and workflow_run chaining. It cites the March 2026 Trivy attack and a new actions/checkout v7 default behavior (effective June 18, 2026).
The five priorities
If you do nothing else:
- Pin all third-party actions to a full commit SHA
- Set default
GITHUB_TOKENpermissions to read-only - Never use
pull_request_targetin public repos - Never interpolate
${{ github.* }}directly intorun:steps - Use OIDC for cloud credentials instead of long-lived secrets
How the trigger attacks work
pull_request_target runs in the base repository's context regardless of PR origin, loading referenced secrets into the runner. The trigger is safe by default (it runs base-branch code, not fork code); the danger is only when you explicitly check out the fork's code, which then executes with secret access — a "pwn request." Any external contributor can open a PR to trigger it, and injected code exfiltrates secrets via e.g. os.environ.get('MY_SECRET') with no merge and no trace.
workflow_run reaches the same place via an extra hop: the downstream workflow runs with write permissions and secret access regardless of what triggered the upstream one. If an upstream pull_request workflow is vulnerable to script injection, an attacker poisons the output artifact via a PR, and the privileged downstream workflow consumes that attacker-controlled content.
What to do
pull_request_target: avoid in public repos. In private repos, require maintainer approval for first-time contributors under Settings > Actions > Fork pull request workflows.workflow_run: prefer triggering directly (e.g.pushonmain) rather than chaining. If you must chain, gate privileged jobs on the upstream trigger type:
jobs:
deploy:
if: github.event.workflow_run.event == 'push'actions/checkoutv7 (as of 2026-06-18) blocks common pwn-request checkouts in bothpull_request_targetandworkflow_runby default, refusing fork PR code unless you setallow-unsafe-pr-checkout: true. Upgrading is a concrete mitigation; do not set that flag.
Caveats
The page states best practices won't make workflows bulletproof — a compromised maintainer or a GitHub-infrastructure zero-day remains out of scope; these steps close the vectors attackers are actively exploiting. Note the pull_request_target default state is safe; the risk is specifically adding a fork checkout, so blanket "never use it" advice is stricter than the mechanism strictly requires. The In-the-wild claim: after the Trivy compromise, an attacker scanned GitHub for pull_request_target-enabled repos and opened several hundred PRs in roughly a day.
Organisations named here
- Shai-Hulud
CVEs named here
- CVE-2025-30066
Technologies named here
- Aikido
- GitHub Actions
- actions/checkout
- Aikido Safe Chain
- Dependabot
- tj-actions/changed-files
- reviewdog/action-setup
- Renovate
- aquasecurity/trivy-action
- pinact
- Harden-Runner
- npm
- bullfrog
- PyPI
- TanStack/router
- Actions Runner Controller
- PyTorch
- OpenSSF Scorecard
- CODEOWNERS
- Ultralytics
- Nx
- GitHub Environments
- OIDC
- Trivy
- Aikido Security
Techniques named here
- pull_request_target abuse / pwn request
- workflow_run privilege chaining
- Script injection via github.* context values
- Prompt injection against AI agents in workflows
- LLM output injection
- GITHUB_ENV / GITHUB_PATH injection
- Artifact overwrite via extraction into workspace
- Secret leakage via broad artifact upload
- Mutable action/tag repointing
- Transitive mutable dependency compromise
- Floating package version compromise
- Secret exposure via command-line arguments
- Secret masking bypass in logs
- Cache poisoning via untrusted PR-influenced cache writes
- Self-hosted runner code execution via public PR
- Persistent runner backdoor via stolen token
- npm trusted publisher token minting via orphaned commit
Threat actors named here
- Shai-Hulud
- tj-actions compromise
- Trivy attack
- aquasecurity/trivy-action tag repointing attack
- Ultralytics attack
- Nx / s1ngularity attack
- PromptPwnd
- prt-scan
- Mini Shai-Hulud TanStack attack
- PyTorch self-hosted runner attack
- Mini Shai-Hulud
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
