After the March 2026 trivy-action tag compromise, what should a team that ran Trivy in CI check, rotate and change?
answer
- the scanner runs with the job's secrets
- force-pushed tags
- an installer the action calls
- dates, versions, digests
basics
~20 sCheck whether any job ran a trivy-action tag below 0.35.0, an unpinned setup-trivy or a malicious Trivy 0.69.4, 0.69.5 or 0.69.6 in March 2026; if so, rotate every secret it could reach, then pin all three immutably.
solid answer
~40 sOn 2026-03-19 stolen credentials were used to publish a malicious Trivy v0.69.4, force-push 76 of 77 trivy-action version tags and replace all 7 setup-trivy tags with an infostealer that ran **before** the real scan, so the scan output looked normal; malicious v0.69.5 and v0.69.6 images followed on Docker Hub on 2026-03-22 (GHSA-69fq-xp46-6x23, CVE-2026-33634). Check run logs from 19 to 20 March, which references you used, and whether a `tpcp-docs` repository appeared under your account. If any job could have run the payload, treat every secret it could reach as exposed and rotate it. Then change the pipeline: pin trivy-action by full commit SHA and confirm what that commit pulls in transitively, pin the Trivy `version` instead of `latest`, reference images by digest, and keep deploy credentials out of the scan job.
go deeper
Recall the outline: in March 2026 trivy-action and setup-trivy tags were force-pushed to credential-stealing code and a malicious Trivy v0.69.4 was published.
Explain why a mutable tag let the attacker swap code under existing workflows, and why the infostealer could reach secrets from inside a scan step.
Walk through the response: check runs and versions against the advisory's windows, rotate every reachable secret, and fix transitive references such as a SHA-pinned action that still pulled setup-trivy by tag.
Treat the scanner as part of the attack surface: decide what credentials a scan job may hold, how its tools are pinned and verified, and how rotation stays atomic.
## What happened The advisory **GHSA-69fq-xp46-6x23** (CVE-2026-33634, critical) describes a continuation of an attack that began in late February 2026. Credential rotation after the first disclosure on 1 March was not atomic, and the attacker kept access. On **19 March 2026** compromised credentials were used to: 1. publish a malicious **Trivy v0.69.4** release through the normal pipeline, reaching GHCR, ECR Public, Docker Hub, the deb and rpm packages and `get.trivy.dev`; 2. force-push **76 of 77** version tags of `aquasecurity/trivy-action` to commits whose `entrypoint.sh` carried an infostealer; 3. force-push all **7** tags of `aquasecurity/setup-trivy` (v0.2.0 to v0.2.6) to malicious commits. On **22 March** separately compromised Docker Hub credentials pushed malicious `aquasec/trivy:0.69.5` and `0.69.6` images. The advisory's exposure windows (UTC) were about 3 hours for v0.69.4, about 12 hours for trivy-action (19 March ~17:43 to 20 March ~05:40), about 4 hours for setup-trivy and about 10 hours for the Docker Hub images. ## Why it matters for a scan job A scanner step runs inside the job, with the job's token, environment and mounted credentials. The injected code ran **before** the legitimate scan, so the scan still produced its normal report and nothing looked wrong. It dumped the runner worker's process memory to extract secrets, swept more than 50 paths for SSH keys, cloud credentials, Kubernetes tokens, Docker configs and `.env` files, encrypted the haul and sent it out. If that failed and a PAT had been supplied to the action, it created a public repository named `tpcp-docs` on the victim's account and uploaded the data there. ## Who was affected, per the advisory | Reference | Affected? | |---|---| | trivy-action tags 0.0.1 to 0.34.2 | yes | | trivy-action 0.35.0 (an immutable release) | no | | trivy-action pinned to a commit after 2025-04-09 | no | | trivy-action pinned to a commit before 2025-04-09 | yes, through setup-trivy during its window | | setup-trivy referenced by tag during its window | yes | | Trivy v0.69.3 or earlier, images by digest, source builds | no | The pre-April-2025 row is the lesson most teams miss: pinning the top-level action by SHA protected its own code, but that old commit still called `setup-trivy` by tag, and the tag was replaced. Current trivy-action pins `setup-trivy` by commit hash in its `action.yaml`. Explicitly passing `version: latest` during the binary window also pulled v0.69.4. ## What to check - Workflow run logs from 19 to 20 March 2026 for jobs using `aquasecurity/trivy-action` or `aquasecurity/setup-trivy`. - Which Trivy versions any runner, image or package mirror pulled; remove v0.69.4 artefacts. - Repositories named `tpcp-docs` in your organisation. - References to old tags: the advisory says the original `0.x` tags were deleted and recreated with a `v` prefix, with v0.0.10, v0.34.1 and v0.34.2 not yet restored at the time, so a workflow still on `@0.34.2` no longer resolves. ## What to rotate If a compromised version could have run, the advisory's instruction is that **all secrets accessible to affected pipelines** are exposed: cloud keys, registry credentials, deploy tokens, PATs, anything in the environment or on disk. Rotation has to be complete and fast; the incident itself grew out of a rotation that left a window. ## What to change - Reference third-party actions by full commit SHA (the general pinning rule is a broader supply-chain topic) and check what that commit references in turn. - Pin the Trivy binary version rather than `latest`, and pull the Trivy image by digest. - Verify downloaded binaries against their sigstore bundle with `cosign verify-blob`, as the advisory demonstrates. - Give the scan job only what scanning needs: a read-only token, no deploy credentials, and no PAT unless the job submits a dependency snapshot. ## The broader lesson The tool that checks the supply chain is itself part of it. A scan step is code from a third party, fetched at run time, executed with whatever the job holds. Treat it like any other dependency of the pipeline: - know exactly which code runs, down to the actions it calls; - give it the least access that still lets it scan; - keep enough run history to answer "did we execute this between these two timestamps" quickly.
- Why did the scan results give no hint that anything was wrong during the trivy-action compromise?The infostealer was injected ahead of the legitimate code: in trivy-action it ran in `entrypoint.sh` before the scan, and in setup-trivy as a step before the real installation. The real Trivy then ran and produced its normal report, so a green or red gate meant exactly what it always did. Detection had to come from run logs, network egress or the `tpcp-docs` fallback, not from the findings.
- Was a workflow that pinned the Trivy container image by digest exposed to the malicious 0.69.5 and 0.69.6 Docker Hub images?No. The advisory lists Trivy images referenced by digest as unaffected, because a digest names exact content and the attacker could only move tags. Workflows that pulled `latest` or the new version tags from Docker Hub during the roughly ten-hour window on 22 to 23 March were exposed.
saying these in an interview costs you the question
- Pinning trivy-action to any commit SHA made a workflow safe during the March 2026 incident.
- A security scanner step only reads the code, so it cannot leak secrets.
- If the Trivy scan output looked normal, the compromised action did not run.
- Rotating only the GITHUB_TOKEN is enough, because it expires when the job ends.
- Re-running the same version tag later fetches the code that ran originally.