Poisoned GitHub Actions
Also tracked as tj-actions · TeamPCP / trivy-action · Axios
Rewrite one tag and every pipeline that trusts it runs your code
75 of 76 version tags force-pushed in a single incident
Git tags are mutable. A version tag like v1 is a pointer, and whoever controls the repository can move it. Most workflows reference actions by tag, so moving the pointer changes what runs everywhere, immediately, with no new release.
In March 2026 attackers force-pushed 75 of 76 trivy-action version tags to malicious code, exfiltrating secrets from every pipeline that ran a Trivy scan. Those stolen credentials then cascaded into PyPI compromises.
The pattern repeats: tj-actions/changed-files, used in 22,000+ repositories, was compromised through four interdependent actions. Axios shipped malicious versions that lived roughly three hours, with the payload hidden in an inserted dependency rather than in Axios itself.
The attack chain
5 of 5 stages are broken by controls we verify. Where nothing we check would have helped, the stage says so.
Compromise an action's repository
Through a maintainer account, a vulnerable workflow, or a chain of dependent actions. The attacker does not need your repository — only one you depend on.
Broken by
- GitHub Org 2FA Required
- GitHub Branch Protection
What we can't verify
These controls harden your organization. They cannot harden a third party's repository — which is why the following stages matter more.
Rewrite the version tags
Force-push existing tags to point at malicious commits. Every consumer pinned to a tag silently picks up the new code on the next run.
Broken by
- Actions Pinned to Commit SHA
- Immutable Releases
Execute inside your pipeline
The action runs with whatever your workflow grants it. Where the default token carries write access, that includes pushing code and cutting releases.
Broken by
- GitHub Workflow Permissions
- Third-Party Actions Restricted
Harvest secrets and OIDC tokens
Workflow secrets and short-lived OIDC credentials are read from the running job and exfiltrated — often base64-encoded into logs.
Broken by
- Third-Party Actions Restricted
- Actions Pinned to Commit SHA
Pivot downstream
Stolen credentials are used to publish to package registries or approve changes, turning one compromised action into a supply-chain incident of its own.
Broken by
- Actions Cannot Approve PRs
- Published Build Provenance
How we verify the layer exists
Each of these reads a specific field from a provider's own API. The exact field is listed in our methodology.
Actions pinned to commit SHA
Verifies your organization enforces SHA pinning. A commit hash cannot be moved, so rewriting a tag has no effect on what your pipelines run — this is the direct answer to stage 2.
Third-party actions restricted
Confirms only GitHub, verified creators, or an explicit allowlist may run — and gives you a kill switch to block a specific action during an active incident.
Immutable releases
Verifies published release assets and tags cannot be overwritten after publication, so a release someone already reviewed cannot be swapped later.
Read-only default CI token
Confirms the default GITHUB_TOKEN is read-only org-wide, so a compromised action cannot push code or cut releases with it.
Actions cannot approve PRs
Ensures a compromised workflow cannot approve its own malicious pull request into your default branch.
What passing these checks does not mean
- ·We read organization-level policy, not the contents of your workflow files. Patterns like untrusted input interpolated into a run step, or pull_request_target checking out fork code, are not covered by these checks.
- ·SHA pinning does not extend automatically to actions that your pinned action itself depends on. Transitive references can still be loosely pinned.
- ·A cooldown before adopting new action versions catches most of these incidents — the Axios window was about three hours — but it lives in your dependency tooling, not in a setting we can read.
Sources
- Wiz — Hardening GitHub Actions
- Wiz — GitHub Actions threat model & defenses
- GitHub — Immutable releases
Would these controls hold in your environment?
Connect read-only and find out in 60 seconds. Free.
Check my posture