Aller au contenu
Français
medium

Trivy compromised a second time with a poisoned v0.69.4 release

Lire cet article en français

16 min read
Trivy, again

Important update, 20 March 2026 This post covers the second episode of the Trivy incident. My first article described the initial compromise of late February and the disappearance of the GitHub repository. New public evidence published on 20 March 2026 shows that a new twist took place on 19 March, with the publication of a compromised v0.69.4 release. The external investigation is still ongoing, so some points remain to be confirmed.

Important update, 23 March 2026 This post initially covered the second episode of the Trivy incident around the compromised v0.69.4 release of 19 March. New analyses published by Socket and StepSecurity now indicate that Docker Hub images 0.69.5 and 0.69.6, pushed on 22 March without a matching GitHub release, also contain indicators of compromise. The latest tag was pointing to 0.69.6 at the time. As I write this update, this point is solidly documented by external researchers, but I keep this extended scope clearly separate from the elements officially confirmed by the GitHub advisory and the Aqua communication, which remain centred on v0.69.4, trivy-action and setup-trivy.

This blog is written in French, and the linked guides are in French. I kept them because they are the underlying references, but be aware of the language before you follow them.

What happened on 19 March?

On 19 March 2026, a Trivy release v0.69.4 was published with malicious code embedded, then propagated through several distribution channels. I thought the Trivy story was behind us: repository restored, public incident, first fixes on the GitHub Actions workflows. But the new analyses published by BoostSecurity show a far more worrying scenario. BoostSecurity considers it highly probable that the same PAT stolen in late February was reused. BoostSecurity also states that its investigation was published early to help community threat hunting, and that some details still need to be consolidated.

In other words, we are no longer talking only about a wiped repository or deleted releases. We are talking about a poisoned release that travelled through the project's normal distribution channels.

Why is this second incident more serious?

The first episode was destruction; this one is infiltration, an attacker managing to publish a malicious artifact as if it were legitimate. During the first episode, the visible effect was brutal: releases deleted, repository replaced, installers broken. It was spectacular, but it remained mostly a destruction incident. In this second act, the risk is different.

BoostSecurity indicates that the v0.69.4 release was distributed through GitHub Releases, Homebrew, AWS ECR, Docker Hub, GHCR, and that a large share of the trivy-action tags were also rewritten to serve malicious code. If this analysis is fully confirmed, we are facing a compromise of the distribution chain, not just of the source repository.

Where did the attack most likely start?

The probable starting point is a stolen PAT that was never revoked. In its analysis, BoostSecurity goes back to the initial compromise of February: a GitHub Actions secret named ORG_REPO_TOKEN, tied to the aqua-bot service account, was exfiltrated through a Pwn Request attack. According to Boost, this token had a very broad scope, being used in at least 33 workflows of the organisation, which made it an extremely dangerous single point of failure. BoostSecurity also considers it very likely that this PAT was not rotated immediately after the initial incident.

This hypothesis fits the publicly observed sequence of events: the aqua-bot service account appears in the actions related to the publication of v0.69.4, to the deletion of a v0.70.0 tag, and to operations on the repositories of the Trivy ecosystem.

How was the poisoned release built to look legitimate?

The attacker prepared two impostor commits, detached from any branch, crafted to blend into an ordinary diff. One targeted actions/checkout, the other aquasecurity/trivy. These commits used credible authors, plausible messages and deliberately discreet modifications to disappear into the noise of a routine change.

The Trivy-side commit introduced three key changes:

  1. a pinning of actions/checkout to a malicious but credible SHA;
  2. the addition of --skip=validate to GoReleaser;
  3. cosmetic changes in the YAML to dilute the real signal in the diff.

This is exactly the kind of detail that should make us think: in principle, pinning an action by SHA is a good practice. But if the SHA itself points to a malicious commit, that good practice becomes a false sense of security.

What role did the typosquatted domain play?

BoostSecurity identified a telling command and control domain: scan.aquasecurtiy.org, a typosquat of the Aqua Security domain with swapped letters in security. According to the analysis, the fake actions/checkout downloaded from this domain several Go files meant to replace components of the Trivy binary, plus a .golangci.yaml file to silence the linter alerts on the injected code.

Still according to Boost, the downloaded files make the intent clear: a modified entry point, a persistent daemon and Unix/Windows specific code. Building on Socket's analysis, BoostSecurity also links this payload to capabilities for in-memory secret theft, collection of SSH keys, cloud credentials and Kubernetes tokens.

What is the timeline of 19 March?

The sequence published by BoostSecurity is particularly instructive.

At 17:43 UTC, the v0.69.4 tag was pushed to the poisoned commit, which triggered the documentation and release workflows. Eight minutes later, at 17:51 UTC, aqua-bot deleted a v0.70.0 tag, which suggests a first attempt abandoned for being too visible. The attacker then apparently came back to v0.69.4 to blend better into the existing version series.

BoostSecurity then indicates that the release pipeline executed a chain that is classic but dangerous in this context: login to the registries, checkout of the code, multi-platform build with GoReleaser, publication of the images and of the GitHub Release. The publication of the compromised release reportedly happened at 18:25:54 UTC.

How far did the downstream propagation go?

This is where the incident truly changes dimension: the poisoned release rode the automated distribution channels.

Homebrew

BoostSecurity documents that at 18:05 UTC, a Homebrew bot opened an automatic PR to integrate trivy 0.69.4 into homebrew-core. The PR was merged at 19:35:58 UTC, which made compromised bottles available on several platforms before an emergency downgrade to 0.69.3 was triggered. StepSecurity also confirms this emergency rollback to v0.69.3.

setup-trivy

BoostSecurity indicates that between 22:06 and 22:08 UTC, aqua-bot published a burst of releases on aquasecurity/setup-trivy, rewriting the version history from v0.1.0 to v0.2.5. BoostSecurity also notes that no workflow was triggered that day on this repository, which suggests publications made directly through the GitHub API. Later, the incident response deleted every tag except the clean v0.2.6, which broke the pipelines pinned to the older versions. StepSecurity confirms that only v0.2.6 was kept as a healthy tag.

trivy-action

BoostSecurity writes that 75 tags out of 76 of aquasecurity/trivy-action were force-pushed to malicious code, with only @0.35.0 remaining intact. StepSecurity, more cautious in its wording, indicates that trivy-action was still compromised at the time of its publication. If accurate, the potential impact is enormous, because this action is widely referenced in GitHub workflows.

Image registries

BoostSecurity states that GoReleaser pushed multi-architecture images to public ECR, Docker Hub and GHCR under the 0.69.4 tag. Here again, if this chain is confirmed end to end, the problem goes far beyond the single GitHub Release binary.

What changed with Docker Hub 0.69.5, 0.69.6 and latest?

On 22 March 2026, Socket reported that new images aquasec/trivy:0.69.5 and aquasec/trivy:0.69.6 had been pushed to Docker Hub without any matching GitHub release or source tag. According to their analysis, these images contain the same indicators of compromise as v0.69.4, notably the reference to the typosquatted domain scan.aquasecurtiy.org, along with artifacts such as payload.enc, tpcp.tar.gz and a fallback reference to tpcp-docs.

StepSecurity published an update on 23 March pointing in the same direction. Their team says it extracted the trivy binary from the aquasec/trivy:0.69.5 and aquasec/trivy:0.69.6 images and found the string https://scan.aquasecurtiy.org through a strings analysis.

The most disturbing point is that the latest tag was then pointing to 0.69.6. In other words, even pipelines that did not explicitly request 0.69.5 or 0.69.6 could pull a compromised image through a simple latest.

I therefore now treat 0.69.4, 0.69.5, 0.69.6 and latest on Docker Hub as untrustworthy during that window, even though the scope officially confirmed by Aqua and the GitHub advisory remains narrower.

Why was the incident response itself disrupted?

The attacker apparently also targeted the community's coordination, not just the code. Another troubling element: BoostSecurity indicates that the initial GitHub discussion of the February incident, #10265, was deleted during the response phase. StepSecurity also reports that this discussion contained active exchanges about the new v0.69.4 compromise.

BoostSecurity also describes a flooding campaign by bot accounts in the replacement discussion, with generic comments meant to drown the useful signals. If true, we are not only talking about a technical compromise, but also about an attempt to jam the community coordination during remediation.

What do we know, what do we suspect, what remains unconfirmed?

Several elements are publicly observable, while others remain at the level of highly probable analysis.

At this point, we can observe publicly that:

  • a v0.69.4 release did exist and was then deleted;
  • an emergency Homebrew rollback to v0.69.3 did happen;
  • setup-trivy was purged to leave only a clean v0.2.6 tag;
  • the community launched a broader audit of the Trivy workflows after the first incident. A public PR mentions 26 findings across 22 workflows and 2 composite actions, including fixes for secret exposure and the addition of explicit permissions: blocks.

On the other hand, some points still sit at the level of very probable analysis, not absolute certainty:

  • that the same PAT is indeed the direct cause of this second episode;
  • that all the cited distribution channels actually served compromised artifacts during the same window;
  • that the full extent of the trivy-action compromise is precisely known.

I prefer to stay rigorous: the clues are very strong, but the external investigation is still active.

What are the real lessons for our pipelines?

1. An organisation secret in GitHub Actions is a major security debt

The most striking point here is not the initial exploitation, it is the blast radius of a secret shared across many workflows. When a PAT potentially grants access to several repositories, releases, tags and discussions, the compromise of a single workflow becomes an organisation-wide compromise.

2. Immediate rotation is not negotiable

If the BoostSecurity hypothesis is correct, this second incident is exactly what happens when a stolen credential is not revoked in time. The twenty-day gap between the two episodes is not a detail: it is an enormous exploitation window.

3. SHA pinning is not enough

Pinning GitHub actions by SHA is necessary, but you also have to validate the provenance of the commit. Check whether it is signed, whether it belongs to the expected history, and whether it is not simply an orphan commit prepared to fool defenders. BoostSecurity notes that the commits used here were unsigned and that neither actions/checkout nor aquasecurity/trivy enforced commit signing.

4. Even good workflows must be treated as attack surfaces

The public audit launched after the first incident is revealing: secrets exposed on the command line, possible shell injections, missing or overly broad permissions. These are not style details. They are entry points.

5. Automated distribution channels propagate a compromised release very fast

Homebrew, OCI images, GitHub Actions: once a release looks legitimate, propagation can be very fast and largely automated. Here, it is precisely this automation that turns a repository incident into a supply chain incident.

What should you do right now if you use Trivy?

If you consumed Trivy between 19 and 23 March 2026, treat the following as untrustworthy:

  • v0.69.4 for binaries and images;
  • aquasecurity/trivy-action on the compromised tags;
  • aquasecurity/setup-trivy before v0.2.6;
  • on Docker Hub, aquasec/trivy:0.69.4, 0.69.5, 0.69.6 and potentially any use of latest during the affected window.

Concretely, you should:

  • search for 0.69.4, 0.69.5, 0.69.6 and latest in your workflows, Dockerfiles, Helm values and manifests;
  • check your CI/CD caches and your mirror registries;
  • audit the Docker Hub pulls performed around 19–23 March;
  • look for any communication towards scan.aquasecurtiy.org;
  • consider as compromised any pipeline that executed an affected Trivy action during the exposure window;
  • perform a full rotation of the exposed secrets, including self-hosted runners and credentials persisted on disk;
  • replace the references with healthy versions and, when possible, with pinned digests rather than floating tags.

Where do I stand?

This second episode is, in my view, even more instructive than the first.

The first showed that a badly designed GitHub Actions workflow could lead to a major compromise. The second shows something harder to hear: once an attacker holds a powerful credential, they can come back later, blend into the project's automation, then turn the build and distribution ecosystem into an attack vector.

The real lesson is therefore not only "do not use pull_request_target carelessly". The real lesson is broader: a CI/CD pipeline must be administered as a critical system, with privilege separation, very short-lived secrets, immediate rotation, mandatory signatures, tag control, provenance verification and fast response capability.

Otherwise, the day the chain breaks, it is not just your repository that goes down. It is the trust of your users that leaves with it.

The new signal on Docker Hub also changes the nature of the lesson. We are no longer talking only about a GitHub release compromised for a few hours, but about the incident persisting in heavily used distribution channels, including through newer tags and latest. It reinforces a simple conclusion: in critical CI/CD, we should no longer consume external images on the fly without quarantine, provenance verification, internal promotion and control before execution.

In the meantime, my personal recommendation is clear: stop using Trivy.

Sources