Security1 distinct publisher2 min readPublished
The maintainers date the second wave to March 19, eighteen days after they disclosed the first one and rotated credentials without doing it all at once, and the only action tag that came through clean was one GitHub had already frozen.
The Watch · Security desk

Compiled by The WatchSomething wrong?How this is made
The mechanism was a checkout swap. Commit `1885610c` repointed the workflow's `actions/checkout` reference at an imposter commit, `70379aad`, which was a composite action that downloaded malicious Go source files from a typosquatted domain [6]. The same change added `--skip=validate` to goreleaser, removing the binary validation step [7]. Tagging that commit was enough to fire the release pipeline [8], and the output went out through GHCR, ECR Public, Docker Hub on both the version and `latest` tags, deb and rpm packages, and get.trivy.dev [9]. Nothing landed on `main`: the malicious code was fetched and built on the ephemeral runner and copied to a `v0.70.0` branch that was never tagged or released [10]. A reviewer reading the default branch would have seen a clean tree. The attempted v0.70.0 release was stopped before it shipped [11].
Across the two action repositories there were 84 published tags. 83 of them pointed at malicious commits and one did not [1]. The survivor is trivy-action 0.35.0, published after GitHub's immutable releases feature was enabled on March 4 [13]. Trivy v0.69.3 held for the same reason, with immutability turned on in the main repository on March 3; v0.69.2 predates that but can still be checked against its sigstore signatures [12]. In both cases the protection was a platform setting applied before publication.
Pinning is where consumers will get this wrong twice. A commit SHA is the standard answer to tag hijacking, and here it works only on the right side of a date: trivy-action began pinning its own dependency in a pull request merged 2025-04-09, so a pin to any earlier commit gives you a safe action that then pulls a malicious setup-trivy during that repository's exposure window [15]. setup-trivy is exposed at every unpinned version [16]. Clear, per the advisory: images referenced by digest, binaries built from source, and the official Homebrew formula, which compiles from source [17]. One custom tap was also compromised, but it needs a deliberate install and is not in the documentation [18].
March 19 is 18 days after the March 1 disclosure [2]. The rotation window that the maintainers say gave the attacker a path back lasted a few days, long enough for a still-valid token to exfiltrate the freshly issued secrets [5]. Everything malicious has been removed from the sources and destinations, and the advisory says it may still sit in intermediary caches [19]. That is the live part now: runner caches, registry mirrors, internal proxies that pulled `latest`. Whatever ran the rewritten `entrypoint.sh` ran an infostealer ahead of the legitimate action code [20], so the scope is set by what those jobs could read.
Ranked by verification strength, evidence, and original report placement.
On March 19, 2026, a threat actor used compromised credentials to publish a malicious Trivy v0.69.4 release.
On March 19, 2026, the attacker force-pushed 76 of 77 version tags in aquasecurity/trivy-action to credential-stealing malware.
The attacker replaced all 7 tags in aquasecurity/setup-trivy with malicious commits.
On March 22, 2026, a threat actor used compromised credentials to publish malicious Trivy v0.69.5 and v0.69.6 Docker Hub images.
The attacker pushed commit 1885610c, which swapped the actions/checkout reference to an imposter commit 70379aad containing a composite action that downloaded malicious Go source files from a typosquatted domain.
The attacker added --skip=validate to goreleaser to bypass binary validation.
Distinct publishers with included, body-backed reporting in this cluster.
1 article · September 3, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
science
TeamPCP hid its infostealer inside the scanners that audit everyone else's code1 distinct publisher
build
Flux moves GitOps' source of truth into registries you own, and mirroring becomes the prerequisite1 distinct publisher
science
A backdoored litellm release turns every CI job that installed it into a credential incident1 distinct publisher
security
The 2,500-org compromise was a Trivy problem. LiteLLM was the closing act.1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Forensically specific, entirely self-reported
The detail here is the kind you cannot fabricate casually: the commit that swapped actions/checkout, the imposter commit it pointed to, the goreleaser flag that skipped validation, the pull request number and merge date that make an old SHA pin unsafe. That specificity is why the reconstruction holds up. What it does not have is a second pair of eyes — every date, count and hash comes from the project that was breached, and no outside researcher, registry operator or downstream user appears in our coverage to confirm any of it.
Every channel reached, no victim count anywhere
Reach is documented thoroughly and impact is not documented at all. The poisoned build went out through five distribution paths including Docker Hub's latest tag, and 83 of the 84 tags across both action repositories pointed at malware, so anything in CI referencing them by name during the window ran it. But nobody has published a pull count, a confirmed-compromise count, or a single named downstream victim — the score reflects proven distribution surface, not measured harm, and we are not going to invent the second number.
Written down, not up
Read the advisory next to what it describes and the register is oddly calm. A near-total tag hijack, a build pipeline subverted with an imposter checkout action, a second wave on separately compromised registry credentials — all of it presented in the flat vocabulary of an exposure matrix, with generous space given to who is not affected. The undocumented compromised Homebrew tap gets a subordinate clause. The story is if anything larger than the language chosen for it.
The only witness is the party at fault
A security vendor is explaining how its own release machinery was used to ship credential-stealing code to its users, twice. That shapes what the document is good at and what it avoids: the mechanics are exact, the not-affected list is expansive, and the awkward question — why a rotation announced on March 1 left a multi-day window an intruder walked back through on March 19 — is answered in the conditional and never followed up. The four-hour takedown time and the restored latest tag are volunteered; how the separate Docker Hub credentials fell is not.
Trustworthy on mechanics, thin on consequence
We would defend the attack narrative — dates, hashes, tag counts, which references were safe and why — because it is internally consistent and specific enough to be falsified by the repository itself. Confidence falls on two counts: the re-entry path is the maintainers' hypothesis rather than a demonstrated finding, and the only account we have is a page captured in September describing events from March, with nobody having revisited it since to say what the damage actually was.