The Trivy CI/CD Hack: Hijacked Pipeline Secrets and the Kubernetes Clusters They Could Reach

In March 2026, Trivy got hacked. Again.

That sounds like a bad headline. It gets worse when you understand what Trivy is supposed to do.

This post starts from zero. No jargon pile-up. If you run apps on Kubernetes, or you have ever heard the words "CI/CD," you should know what happened and what to do about it.

First: what is Kubernetes?

Kubernetes (often called K8s) is a system that runs your apps in containers across a pool of servers.

You tell it: "I want three copies of my app running." It keeps them running. If one crashes, it starts another.

Most companies do not log into servers by hand anymore. They ship code through automated pipelines. Kubernetes is where that code ends up.

Next: what is CI/CD?

CI/CD means the automated assembly line that builds and ships your software.

Roughly:

  1. A developer pushes code to GitHub.
  2. A pipeline wakes up (often GitHub Actions).
  3. The pipeline builds the app, runs tests, scans for security issues, and deploys.

Think of CI/CD as the factory between "code on a laptop" and "app running in production."

That factory holds a lot of keys. Passwords to cloud accounts. Tokens to push container images. Credentials to update the Kubernetes cluster.

So what is Trivy?

Trivy is a free, popular security scanner.

It looks at:

  • your container images ("does this base image have known bugs?")
  • your config files ("is this Kubernetes YAML risky?")
  • sometimes your code dependencies

Thousands of teams plug Trivy into CI/CD. It runs automatically on every code change. Before anything reaches Kubernetes, Trivy is supposed to say: "hold on, this has a problem."

It is one of the good guys. A guard at the factory door.

The paradox: the guard got robbed

That is why this hack stings.

You installed Trivy to protect your pipeline. Attackers compromised Trivy itself and used that trust to attack your pipeline.

The guard became the entry point.

You did not download a shady tool from a forum. You used a well-known scanner from a respected security company (Aqua Security). Your pipeline ran it because best practice said to.

That is the paradox: the safety tool became the risk.

What actually happened (March 2026)

Attackers broke into Trivy's publishing systems. They tampered with three things at once:

  1. A bad Trivy program release (version 0.69.4)
  2. The GitHub Action most people use to run Trivy in pipelines (aquasecurity/trivy-action)
  3. A helper action that installs Trivy (aquasecurity/setup-trivy)

Here is the sneaky part. They did not ask you to change your config.

They moved the labels.

Many pipelines say: "use Trivy version 0.34.2." That version number is a tag - a sticky note on a specific piece of code. The attacker peeled off the sticky notes and stuck them on malicious code instead. In numbers: they reassigned 76 of the 77 version tags in trivy-action and all 7 tags in setup-trivy to point at their payload, so nearly every pinned version silently became poisoned at once.

Your file still said @0.34.2. The code behind that label was different.

Analogy: you saved a contact as "Mom" in your phone. Someone changed the phone number behind "Mom." You tap the same name. You reach a stranger.

The malicious code ran before the real scan. It searched the pipeline machine for secrets:

  • GitHub tokens
  • cloud passwords (AWS, Azure, GCP)
  • keys to push container images
  • SSH keys
  • database passwords in config files

And investigators found it was especially interested in Kubernetes credentials.

It hunted for kubeconfig files and cluster tokens. More on that in a moment.

Then it encrypted what it found and tried to send it to the attacker over the internet.

This was serious enough that Germany's federal cyber agency (BSI) issued an official warning. They rated it CVSS 9.4 (critical) and reported real compromise cases linked to the campaign inside Germany. Their advisory explicitly lists Kubernetes tokens among the stolen credential types and urges immediate secret rotation if a affected Trivy version ran in your pipelines. Read the full warning here: BSI Cybersicherheitswarnung 2026-237970-1032 (PDF).

For more detail, see The Hacker News write-up and Aqua Security's advisory.

What is a kubeconfig, and why did attackers want it?

A kubeconfig is a small config file. It is the remote control for a Kubernetes cluster.

It usually contains:

  • the cluster's address (where to connect)
  • a username or service account identity
  • a token or certificate (the password proving you are allowed in)

Developers and CI/CD pipelines often keep a kubeconfig on the build machine so the deploy step can say: "apply this update to production."

That file is gold. Whoever holds it can often:

  • list everything running in the cluster
  • deploy new apps
  • read secrets stored inside the cluster
  • change permissions

Security researchers analyzing the Trivy malware found it specifically scanning for kubeconfig files and Kubernetes tokens. Not as an afterthought. As a target.

Advisories from Aqua Security, Microsoft, and others described the stealer sweeping dozens of filesystem paths, dumping CI runner memory, and collecting anything that looked like cluster access - including files under ~/.kube/config and in-cluster service account tokens.

Why this matters for Kubernetes clusters

The hack usually started in CI/CD, not inside the cluster.

But it did not stop there.

Investigators reported a methodical follow-on: stolen kubeconfig files and tokens were used to log into clusters, enumerate what was inside, and in some cases deploy persistent backdoors - malicious workloads left running after the pipeline job finished.

Microsoft's threat research noted the same infrastructure was later seen conducting reconnaissance against Kubernetes environments (including GKE), issuing Kubernetes API requests with path-traversal payloads to probe for weak cluster endpoints. Kaspersky tied Trivy, Checkmarx, and litellm together as one campaign and urged victims to check for suspicious pods and other signs of cluster compromise, not just leaked secrets in CI.

The attack chain, in plain terms:

  1. Poison Trivy in your pipeline.
  2. Steal kubeconfig (and other secrets) from the build machine.
  3. Connect to your cluster using those stolen credentials.
  4. Explore and infect - look around, grab more secrets, deploy bad containers if permissions allow.

That is why this is a Kubernetes story, not just a "GitHub got hacked" story.

How they actually took over a cluster

Researchers now track the group behind this campaign as TeamPCP. It turned out Trivy was not their only target, and not their last one.

Three weeks after the Trivy compromise, security firm Endor Labs caught the same group backdooring litellm, a hugely popular open-source library (95 million downloads a month) that lets apps talk to different AI providers through one API. Different tool, different package registry (PyPI instead of GitHub Actions), but the Kubernetes attack code inside the payload was nearly identical. That overlap is what let researchers connect the two incidents and describe, in detail, what the malware does once it lands inside a cluster.

Here is the playbook, in plain terms:

  1. Find a Kubernetes service account token on the compromised machine. CI runners and, in the litellm case, production pods often have one sitting at a well-known file path.
  2. List every node in the cluster. With that token, the malware calls the Kubernetes API and enumerates every node, workers and control-plane alike.
  3. Deploy a lookalike pod to each one. Each pod runs in kube-system - the namespace where real system components already live, so it blends in. It asks for privileged: true, hostPID, and hostNetwork, and mounts the entire host filesystem into itself. Critically, it tolerates every taint, the setting that normally keeps ordinary workloads off control-plane nodes. That one line is what let it schedule anywhere, including nodes that were supposed to be off-limits.
  4. Chroot into the host and drop a backdoor. With that pod running, the attacker effectively has root on the underlying node, not just inside a container. It installs a small persistence script disguised as a desktop service (a fake "System Telemetry Service" via systemd), then the pod itself terminates and is never restarted, so there is no long-lived workload left in kubectl get pods to notice.
  5. Phone home quietly, and know when to go dark. The backdoor sleeps for five minutes, then checks in with a command-and-control server every 50 minutes for further instructions. Anything it downloads gets a filename designed to look like a routine database process, so it does not stand out in a process list. It even carries a kill switch: if the server ever points it to a page mentioning "youtube," it goes dormant instead of continuing.

None of that needed a Kubernetes vulnerability. It needed one leaked token with permission to create pods, and a cluster that let a pod ask for privileged access, host networking, and every taint toleration, and simply granted it.

That is the uncomfortable lesson. The privilege escalation was not exploiting a bug in Kubernetes. It was Kubernetes working exactly as configured, on a cluster that never told a workload "no."

It also reframes the timeline. TeamPCP moved through Aqua Trivy, then Checkmarx's KICS scanner, then npm packages, then litellm on PyPI, all inside about a month. Every compromise handed them credentials that opened the next door. The pattern is deliberate: they target security and infrastructure tooling specifically, because that software already carries the elevated access an attacker would otherwise have to fight for. (Full technical writeup: Endor Labs' analysis of the litellm compromise.)

The pipeline often holds the keys to the kingdom:

  • kubeconfig files with direct cluster admin access
  • tokens that can upload a poisoned container image the cluster will happily pull
  • access to the Git repo that tells GitOps tools (like Argo CD) what to deploy

Steal a kubeconfig and an attacker may not need to break in through a bug. They use your own keys.

Your cluster trusts what CI/CD sends it. If the factory is compromised, production is compromised.

If you think you were affected: fix it now

If your pipeline ran a compromised Trivy action around March 19-20, 2026, assume secrets that job could touch are stolen. Do not wait for proof. The BSI warning aligns with vendor guidance: if a compromised version ran, treat all secrets the pipeline could access as exposed and rotate them immediately.

Step 1: rotate secrets - especially kubeconfig and cluster tokens.

Change passwords and tokens for anything that pipeline could reach. Cloud accounts. GitHub tokens. Registry credentials. Database passwords.

Rotate every kubeconfig and cluster credential the job could touch. Revoke old tokens at the cluster level, not just delete the file from CI. Assume the attacker already copied it.

Step 2: audit the cluster itself.

Do not only fix CI. Check what happened inside Kubernetes:

  • unexpected pods or deployments you did not create
  • new service accounts or role bindings with broad permissions
  • secrets accessed or exported around the same dates
  • API audit logs showing logins from unknown IPs

Investigators reported methodical cluster follow-up after kubeconfig theft. Treat the cluster as potentially compromised, not just the pipeline.

Step 3: check your CI logs.

Look at pipeline runs from those dates. Weird outbound network traffic is a red flag.

Step 4: look for a repo called tpcp-docs.

Advisories reported attackers sometimes created a public repo with that name to dump stolen data. If you see it in your GitHub organization, treat it as a confirmed breach.

Step 5: upgrade to known-safe versions.

At the time of the advisory, safe references included trivy-action v0.35.0, setup-trivy v0.2.6, and Trivy binary v0.69.3. The BSI and Aqua Security both recommend pinning GitHub Actions to full commit SHAs, not movable version tags. Check Aqua Security's advisory for the latest guidance before you pin anything.

Rotating secrets hurts. It is still cheaper than an attacker deploying into your cluster.

How to prevent the next one

You cannot eliminate risk. You can make attacks much harder.

1. Pin tools to exact snapshots, not version labels

Version tags can move. Commit hashes cannot.

Instead of trusting @0.34.2 forever, pin the full commit SHA of the action. Ugly? Yes. Safer? Also yes.

Same idea for the Trivy scanner itself. Pick a version you trust. Do not float on "latest."

2. Stop storing kubeconfig in CI

If you can avoid it, do.

Prefer short-lived credentials. Use cloud-native identity (Azure Workload Identity, AWS IAM roles for service accounts) so the pipeline authenticates without a long-lived kubeconfig file sitting on disk.

If CI gets hacked, you want the blast radius small - and you do not want a cluster admin file waiting in ~/.kube/config.

3. Give CI/CD less power

The pipeline should not hold admin keys to everything.

Use short-lived credentials. Give each job only what it needs for that one task. On Azure, Workload Identity lets apps authenticate without storing long-lived passwords in GitHub. AWS has similar patterns.

If CI gets hacked, you want the blast radius small.

Here is the catch, though. Short-lived is not the same as safe. A federated credential (OIDC to AWS, Azure, GCP) still exists in memory for the life of the job, and this campaign's malware was dumping runner process memory in real time. It even grabbed AWS credentials straight from the instance metadata service, which are already short-lived by design. If the token is live and the attacker uses it in the same minute it was minted, "expires in 15 minutes" does not save you.

What actually would have stopped the Kubernetes takeover described above is scope, not just lifetime. If the identity a Trivy step assumes can only push one image to one registry, a stolen live token gets the attacker a 403 on kubectl get nodes, because that permission was never granted in the first place. Two things make this real:

  • Scope the trust policy, not only the permission policy. With GitHub Actions OIDC, restrict which repo, branch, or workflow file can even assume the role, using the sub claim. Not just "what can this role do," but "who is allowed to become this role at all."
  • Split scanning from deploying. If the Trivy step and the "push to registry" step share one broad role for convenience, compromising the scan compromises the push too. Separate jobs, separate narrowly-scoped identities, and a compromised scan step has nothing downstream to abuse.

Short-lived limits how long a stolen credential is useful. Single-purpose limits what it can do at all while it is still live. You want both.

4. Control where CI can call on the internet

Stolen secrets need to phone home. Tools like StepSecurity harden-runner limit which websites a pipeline job can reach. Unknown destinations get blocked or logged.

Malware hates a locked door.

5. Keep scanning. Just scan smart.

Do not remove Trivy because it was attacked once. You still need guards at the door.

Just treat the guard like any other piece of software: pin a safe version, verify what you run, and do not assume a famous name means "automatically safe forever."

6. Protect Kubernetes even if CI fails

Assume CI might break someday. Inside the cluster:

  • block risky configs before they run (policy tools like Kyverno)
  • specifically, block or restrict privileged pods, hostPID, hostNetwork, and broad taint tolerations for anything outside a short allowlist of real system components. That combination is exactly what let the malware above schedule onto every node, control plane included.
  • limit which pods can talk to which (network policies)
  • require human review before production changes (GitOps with pull requests)

Layers. If one wall falls, another still stands. A stolen token is bad. A stolen token that still cannot deploy a privileged pod to your control plane is a much smaller incident.

What I am doing about it

I updated two public platform projects on my GitHub to bake these lessons in.

Practical AKS - an Azure Kubernetes cluster built step by step. The CI pipeline uses SHA-pinned GitHub Actions (so tags cannot silently move), harden-runner to control outbound traffic, Workload Identity instead of stored cloud passwords, Azure Key Vault for secrets, strict container permissions, and Trivy scanning on pinned safe versions.

EKS IDP Platform - a similar story on AWS EKS. Same CI hardening, plus cluster guardrails: Kyverno policies, Cilium networking, GitOps with Argo CD so deploys stay reviewable.

The point is not perfection. The point is the path from laptop to cluster should not be the softest target in the building.

Your scanner sits on that path. It sees the same secrets your deploy step uses. After March 2026, that is obvious. Treat CI/CD like part of production security, not a side alley.

The whole post in four lines

  • Trivy scans software for vulnerabilities before it ships. In March 2026, attackers hacked Trivy, stole CI/CD secrets, and hunted kubeconfig files to break into Kubernetes clusters.
  • The malware did not stop at the pipeline. Stolen credentials were used to deploy privileged pods to every node, tolerating every taint to reach even the control plane, then drop a quiet backdoor.
  • The same group (TeamPCP) reused the identical Kubernetes attack code weeks later in an unrelated litellm supply chain compromise, this is a repeatable playbook, not a one-off.
  • Fix it: rotate kubeconfig and cluster tokens, audit the cluster for suspicious pods, check CI logs, upgrade to safe versions.
  • Prevent it: pin exact tool versions, keep kubeconfig out of CI, limit permissions, control outbound traffic, and keep cluster policies as a backup wall.

The guard at the door needs guarding too.

Sources and further reading

  • Aqua Security advisory: Trivy ecosystem supply chain temporarily compromised. The vendor's own advisory and remediation guidance.
  • Microsoft Security: Detecting, investigating, and defending against the Trivy supply chain compromise. Detection guidance plus the GKE reconnaissance findings.
  • Wiz: Trivy Compromised by TeamPCP. Attribution and timeline of the TeamPCP campaign.
  • Socket: Trivy Under Attack Again, GitHub Actions Tag Compromise. The tag-reassignment mechanics (76 of 77 tags) in detail.
  • Kaspersky: Trojanization of Trivy, Checkmarx, and LiteLLM. Ties the separate compromises into one campaign.
  • Endor Labs: TeamPCP isn't done. The technical analysis of the Kubernetes takeover payload via the litellm compromise.
  • BSI Cybersicherheitswarnung 2026-237970-1032 (PDF). Germany's federal cyber agency advisory (CVSS 9.4).