Trivy Compromised: How TeamPCP Poisoned Over 10,000 CI/CD Pipelines and What to Do Now

If your CI/CD pipeline uses Trivy — and statistically speaking, it probably does — you need to read this. Between March 19 and 23, 2026, the threat group TeamPCP compromised Aqua Security’s Trivy vulnerability scanner, injecting credential-stealing malware into all official distribution channels at once. This is CVE-2026-33634, with a CVSS score of 9.4, and it affected more than 10,000 CI/CD workflows worldwide.

Here we explain exactly what happened, how the attack worked, and the concrete steps you need to take right now.


What is Trivy and why this matters

Trivy is the most widely adopted open source vulnerability scanner in cloud-native CI/CD. It runs as a GitHub Action on every PR, every merge, every deployment — and it runs with access to pipeline secrets by design. That’s exactly why it was the target. Compromising Trivy doesn’t just give the attacker your code: it gives them your cloud credentials, your SSH keys, your Kubernetes tokens, your Docker configuration, and everything else your pipeline touches.


How the attack occurred

The attack had two phases and exploited a single root cause: incomplete credential rotation from a previous incident.

Phase 1 — March 19, 2026: TeamPCP gained access using credentials stolen during an earlier, separate breach of Aqua Security’s infrastructure that was never fully remediated. With those credentials:

  • They forced malicious commits into 76 of 77 version tags of aquasecurity/trivy-action and into all 7 tags of aquasecurity/setup-trivy
  • They published a poisoned binary as the official v0.69.4 release on GitHub Releases, Docker Hub, GHCR, ECR Public, and get.trivy.dev
  • They impersonated legitimate maintainers to make the commits appear authentic

The injected payload ran before the actual Trivy scan: it collected environment variables, swept the filesystem for cloud and infrastructure credentials, encrypted the results, and exfiltrated them to attacker-controlled infrastructure. Then it launched the real Trivy scan, which completed with normal output. Operators saw no errors. Pipelines appeared to work. The theft was invisible.

Phase 2 — March 22 and 23: Three days later, using Docker Hub credentials compromised separately, TeamPCP uploaded new malicious images: 0.69.5, 0.69.6, and the latest tag — bypassing all GitHub-based controls that had been put in place. This extended the exposure by approximately 10 additional hours before Docker quarantined the images on March 23.

Expansion — March 23 and 24: Using tokens stolen from a bot account (Argon-DevOps-Mgt) that connected two GitHub organizations at Aqua, TeamPCP defaced 44 repositories in Aqua’s internal aquasec-com org and expanded the attack to Checkmarx KICS, LiteLLM (PyPI packages 1.82.7 and 1.82.8), and VS Code extensions on OpenVSX.


Affected versions — the complete list

Docker Hub images:

  • aquasec/trivy:0.69.4, 0.69.5, 0.69.6, latest (during March 19–23)
  • Last known clean version: aquasec/trivy:0.69.3

GitHub Actions:

  • aquasecurity/trivy-action — all tags except commit SHA 57a97c7 (v0.35.0)
  • aquasecurity/setup-trivy — all tags except commit SHA 3fb12ec (v0.2.6)

Downloaded binaries:

  • v0.69.4 from GitHub Releases or get.trivy.dev

Attention: mirror.gcr.io may be serving cached malicious images — always use fixed-digest references.

Compromised digests to look for:

  • sha256:27f446230c60bbf0b70e008db798bd4f33b7826f9f76f756606f5417100beef3
  • sha256:425cd3e1a2846ac73944e891250377d2b03653e6f028833e30fc00c1abbc6d33

Immediate response checklist

Step 1 — Determine if you were exposed

Review your pipeline logs, your local image store, and your Artifactory or Nexus caches for the digests or tags mentioned above. Your exposure window is: any Trivy execution between March 19 at 18:24 UTC and March 23 at 01:36 UTC using the affected tags.

Step 2 — Rotate everything

If any Trivy scan ran a compromised version, treat all secrets accessible from that pipeline as compromised. Immediately rotate:

  • GitHub tokens and Personal Access Tokens
  • Cloud provider credentials (AWS, GCP, Azure)
  • Docker registry tokens
  • SSH keys
  • Kubernetes tokens
  • Database passwords accessible from the build environment

Special case: If you ran the compromised image with the Docker socket mounted (-v /var/run/docker.sock:/var/run/docker.sock), treat the entire host as compromised — that mount grants root-level access to the node.

Step 3 — Pin to secure versions

  • Binary: use aquasec/trivy:0.69.3 or wait for a new verified release from Aqua Security
  • GitHub Action: pin to aquasecurity/trivy-action@57a97c7 (not @v0.35.0)
  • setup-trivy: pin to aquasecurity/setup-trivy@3fb12ec

Going forward: always pin your GitHub Actions to commit SHAs, never to mutable tags. This attack demonstrated at scale that version tags can be silently redirected.

Step 4 — Verify exposure to LiteLLM and Checkmarx

If your stack uses LiteLLM, look for the compromise indicator litellm_init.pth and rotate all secrets. If you use Checkmarx KICS, verify you’re not running the compromised GitHub Action from March 23.


The lesson nobody wants to learn

This attack occurred because incomplete credential rotation from a previous incident left a door open. TeamPCP didn’t need a zero-day. They got in through credentials that should have been revoked months earlier.

The technical lesson is clear: when you rotate credentials after an incident, the rotation has to be atomic and complete. A single valid token that connected two organizations was enough to compromise 44 repositories and extend the attack for days.

The broader lesson: the tools you use to secure your pipeline are part of your attack surface. Your vulnerability scanner runs with elevated privileges. Your linter runs with elevated privileges. Everything in your build chain does. Pinning to commit SHAs — not mutable tags — is no longer optional hygiene: it’s the minimum baseline.


Resources


Does your team use Trivy in production? Have you already rotated your secrets or are you using some alternative method for dependency verification? Let us know in the comments.