Your Security Scanner Was the Attack: The Trivy Supply Chain Compromise
If you ran Trivy in your CI/CD pipeline between late February and March 22, 2026, you may have handed your cloud credentials to an attacker. Not because of a misconfiguration. Not because you made a mistake. Because the scanner itself was the payload.
Here's what happened, what the attack actually looked like under the hood, and — more importantly — why the advice you've been following to protect against this class of attack wasn't enough.
What Got Compromised
Aqua Security's open-source Trivy vulnerability scanner was hit with a multi-stage supply chain attack. Threat actors obtained stolen credentials and used them to force-push malicious commits to version tags in the `aquasecurity/trivy-action` and `setup-trivy` GitHub repositories. The attack ran in three waves:
- Late February 2026: Initial breach, malicious code injected
- March 1: Aqua attempted credential rotation — incomplete, attacker maintained access
- March 22: Attacker attempted to reestablish foothold, triggering detection
The malicious code executed *before* the legitimate Trivy scanning logic ran. Pipelines completed normally. Nothing looked wrong. While your security scan was finishing successfully, the payload was already exfiltrating API tokens, AWS/GCP/Azure credentials, SSH keys, Kubernetes tokens, and Docker configuration files.
Safe versions are: Trivy binary 0.69.2 or 0.69.3, `trivy-action` v0.35.0, `setup-trivy` v0.2.6. If you ran v0.69.4, treat all secrets accessible during those pipeline runs as compromised and rotate immediately.
How the Malicious Commit Slipped Through
This is where it gets worse. The attacker didn't just poison the Trivy release — they also manipulated a dependency commit in `actions/checkout` in a way that exposed a structural weakness in how GitHub resolves SHA references.
The malicious commit in Trivy's release workflow was a 14-line diff. Twelve of those lines were cosmetic: a trailing space removed, single quotes swapped for double quotes, the kind of change that makes a reviewer's brain go idle. The two lines that mattered changed the `actions/checkout` SHA pin.
The version comment — `# v6.0.2` — stayed exactly the same. Only the hex string changed. And the new SHA pointed to an orphaned commit sitting in a fork of `actions/checkout`, not in the official repository at all.
Here's the part GitHub's documentation doesn't emphasize: GitHub's architecture makes fork commits reachable by SHA from the parent repository. When the Actions runtime resolved that SHA, it fetched the commit, found valid-looking code, and ran it. No warning in the run log. No signal that this commit came from outside the repository's branch history.
SHA pinning guarantees you get the same commit every time. It does not guarantee that commit was ever part of the upstream project.
The orphaned commit itself was crafted to look routine — spoofed author metadata, a reference to a real closed PR, no signature. The social engineering payload on the Trivy side was five characters: `# v6.0.2`. That comment made reviewers skip right past the hex string that had changed.
The IOCs You Need Right Now
Block these at the perimeter and hunt your logs:
- C2 domain: `scan.aquasecurtiy[.]org` (typosquat — note the extra 'u') — hunt DNS query logs
- C2 IP: `45.148.10.212` — hunt outbound connections
- Cloudflare tunnel: `plug-tab-protective-relay.trycloudflare.com` — hunt DNS logs for lateral movement and exfiltration
- GitHub exfiltration repo: Unauthorized creation of a repo named `tpcp-docs` in your GitHub org — check audit logs
- Blockchain C2: `tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io` — this is ICP (Internet Computer Protocol) infrastructure; standard domain takedowns can't touch it
That last one is significant. The attacker used a decentralized blockchain endpoint as a command-and-control channel specifically because it resists takedown. This is a tradecraft escalation worth tracking — this pattern will appear in other campaigns.
Aqua has engaged Sygnia for forensics and has revoked all credentials, transitioned away from long-lived tokens, and removed malicious artifacts from distribution channels. Commercial Aqua products were unaffected due to architectural isolation from the open-source build environment.
What Actually Protects You
SHA pinning is still better than mutable version tags — it blocks the most common attack vector. But the Trivy attack exposes a gap that pure SHA pinning can't close.
Before accepting any SHA change in a PR: click through to that commit in the target repository. GitHub shows a yellow banner on orphaned fork commits: *"This commit does not belong to any branch on this repository."* That's a hard no. Any valid SHA for a GitHub Action should trace back to a release branch or tag in the official repo, not a disconnected fork commit.
You can automate this check. The GitHub API endpoint `repos/{owner}/{repo}/commits/{sha}/branches-where-head` returns an empty list for orphaned commits. Run this in your CI lint step or pre-commit hooks.
Beyond that: require signed commits on workflow file changes, restrict your GitHub Actions to an org-level allowlist, mirror the actions you depend on into your own org (which eliminates fork reachability entirely), and require SLSA artifact attestations on released binaries.
The Actual Takeaway
The Trivy attack worked because it stacked bypasses: compromised maintainer credentials bypassed code review, GitHub's fork-reachability architecture bypassed SHA trust assumptions, and `--skip=validate` was added to GoReleaser to strip build-time integrity checks. Every control was individually subverted.
No single fix closes this. SHA pinning is the floor, not the ceiling. Verify what those SHAs actually point to before you trust them.
If you ran compromised Trivy versions, assume full credential exposure and act accordingly. The 30-day window since the initial breach means you may be looking at a longer blast radius than a single pipeline run.