The tool you use to scan your containers for vulnerabilities spent about twelve hours stealing your secrets.1 That’s the short version.
The longer version involves compromised credentials, 75 of 76 poisoned version tags, a typosquatted exfil domain designed to look like the legitimate vendor, and a systemd service installed on developer machines to make sure the theft survived reboots. Oh, and this is the second time Trivy has been compromised in roughly a month.
The irony writes itself. The security scanner as the attack vector. Twice.
What happened
Between March 19 at 17:43 UTC and March 20 at 05:40 UTC 2026, a threat actor with access to compromised Aqua Security developer credentials made a series of deliberate, staged modifications to Trivy’s GitHub presence.
First: a malicious binary. The attacker pushed a poisoned Trivy release tagged v0.69.4. Not a modified Action. The core tool itself.
Then: the GitHub Actions. Using force-push, the attacker overwrote 75 of the 76 existing version tags on the trivy-action and setup-trivy GitHub Actions.2 Force-push lets you rewrite a tag to point to different code. Anyone whose CI pipeline referenced a version tag, which is almost every CI pipeline using Trivy, was now pulling malicious code.
Three components. Core binary, trivy-action, setup-trivy. All compromised in the same window.
What it stole
The malware was an infostealer targeting specifically the things that live in CI/CD environments. SSH keys. Cloud credentials for AWS, GCP, and Azure. Database credentials. Git and Docker configs. Kubernetes service account tokens. Crypto wallets if present.
This is a targeted list. Whoever built the payload understood what CI runners have access to. Not random files. The specific credential types that give you lateral movement, cloud access, and persistent presence across infrastructure.
Exfiltration went to scan.aquasecurtiy[.]org.3 Read that carefully: a-q-u-a-s-e-c-u-r-t-i-y. Not “aquasecurity.” One transposed letter, in a domain constructed to look like official Aqua Security infrastructure. Most monitoring systems aren’t looking for typosquatted domains that closely resemble the legitimate vendor. In a CI run that’s already talking to Aqua’s real infrastructure, a second request to something that looks almost identical would be easy to miss.
The payload sent data as an encrypted HTTP POST. Encrypted, so any TLS inspection that wasn’t specifically watching for that domain would see legitimate-looking traffic.
The persistence that makes this worse
On developer machines, the malware installed a systemd service. This is the detail that separates “someone ran a bad CI job” from “someone has a persistent foothold.”
A systemd service survives reboots. It runs on startup. It runs in the background. If you ran Trivy from your local machine during that window, your machine may have had an active infostealer running long after the compromised package was patched upstream. Long after you updated your Trivy version. Long after the incident was declared resolved.
Credential rotation alone isn’t sufficient if the service is still running. You’d need to identify and remove the service, then rotate credentials, then audit for what may have already been exfiltrated.
The second time in a month
This is Trivy’s second supply chain compromise in roughly four weeks.1 The first, in late February or early March 2026, was a different attacker using a different technique. That one exploited a misconfigured pull_request_target workflow to steal a personal access token from the repository. Different vector, different outcome, different actor.
Two separate attackers. Two separate compromises. One month apart. Same project.
This isn’t coincidence and it isn’t bad luck. High-value open-source security tools are targets specifically because of who uses them and what those users have access to. A DevSecOps team running vulnerability scans has credentials to everything worth scanning. That’s the value proposition of targeting the scanner.
Worth keeping distinct from our March 27 coverage of the GlassWorm campaign, which used an entirely different compromise mechanism targeting different infrastructure. These are separate events. The common thread is supply chain as attack surface, not shared actors or infrastructure.
Why tag-pinning failed and what actually works
Most CI security guidance says to pin your GitHub Actions to a specific version. Fewer people do it than should. This attack shows why the standard guidance isn’t enough.
Version tags in GitHub can be force-pushed. That’s what happened here. The attacker didn’t create a new tag and trick people into switching to it. They moved existing tags to point to malicious code. Anyone running aquasecurity/trivy-action@v0.20.0 or any other version tag was getting whatever that tag pointed to at the time the pipeline ran.
The way to actually prevent this is commit SHA pinning. Instead of referencing a version tag by name, you reference the specific commit hash the tag pointed to when you validated it. Commit hashes cannot be rewritten. They’re cryptographic identifiers of specific code states. You can force-push a tag to a different commit. You cannot make a different commit have the same SHA as the original.
A workflow that looks like this:
uses: aquasecurity/trivy-action@a20de5420d57c4102486cdd9349b532c1184c37
…is immune to tag-force-push attacks. The specific commit is what you get, regardless of what any tag points to. Most CI pipelines don’t do this, because it requires updating the SHA when you want to upgrade, and that’s a friction point. It’s a friction point worth accepting.
What to do now
If your pipelines ran Trivy between March 19 17:43 UTC and March 20 05:40 UTC, treat this as a confirmed credential compromise. Not “possible compromise.” Assume anything the CI runner had access to was exfiltrated.
That means: audit every pipeline run in that window. Rotate every credential the runner could access. SSH keys, cloud provider credentials, database passwords, API tokens, all of it. Kubernetes service account tokens. If it lived in the runner environment, it’s compromised.
If you ran Trivy from a developer machine in that window, you have a different problem. Check for a systemd service that shouldn’t be there, remove it, then rotate credentials from that machine.
Whether or not you were in the window: SHA-pin your GitHub Actions. All of them, not just Trivy. Tags are mutable. Commit hashes aren’t. This class of attack becomes much harder when your pipelines reference commits instead of tags.
The deeper question is trust. Trivy is a good tool, widely used, with a legitimate security purpose. Two supply chain compromises in a month don’t change that, but they change what you need to verify before trusting any tool in that position. Vendor-signed releases. SHA pinning. Active monitoring for unexpected outbound traffic from CI runners, including to domains that look almost like the right domain but aren’t quite.
Your security scanner is doing the right job. Someone noticed that, and tried to use it against you. Build your pipelines like they’ll try again.
Socket - Trivy under attack again with GitHub Actions compromise - https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise ↩ ↩2
Aqua Security advisory GHSA-69fq-xp46-6x23 - https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 ↩
Wiz - Trivy compromised analysis and exfiltration details - https://www.wiz.io/blog/trivy-compromised-teampcp-supply-chain-attack ↩