Skip to main content
Technical March 31, 2026

When Trusted Security Tools Turn Against You: The TeamPCP Campaign and Why Runtime Protection Is No Longer Optional

In March 2026, the threat actor TeamPCP compromised Trivy, KICS, and LiteLLM — turning trusted security tools into credential stealers across thousands of CI/CD pipelines. We break down how the attacks cascaded, why traditional defenses failed, and how tailored AppArmor profiles enforce runtime protection that stops compromised components regardless of how they were infected.

H

Hannes Ullman

bifrost security

When Trusted Security Tools Turn Against You: The TeamPCP Campaign and Why Runtime Protection Is No Longer Optional

When Trusted Security Tools Turn Against You: The TeamPCP Campaign and Why Runtime Protection Is No Longer Optional

The security tools you rely on every day, your vulnerability scanners, your CI/CD actions, your dependency checkers, you have always assumed they are as secure as they possibly can be. That they are part of the solution, never the problem. That the software watching over your software is itself beyond reproach.

The events of March 2026 proved that assumption wrong.

Over the course of a month, a threat actor calling themselves TeamPCP compromised Aqua Security’s Trivy vulnerability scanner, Checkmarx’s KICS, and BerriAI’s LiteLLM AI gateway — weaponizing each tool against the very organizations that trusted them. The campaign spanned PyPI, npm, Docker Hub, GitHub Actions, and OpenVSX (SecurityWeek: From Trivy to Broad OSS Compromise). It is, by any measure, one of the most extensive open-source supply chain operations ever publicly documented.

And it raises a question every engineering team needs to answer: when your security scanner is the way in, what’s left to protect you?

What Happened

The campaign unfolded in waves.

In late February, TeamPCP exploited a misconfiguration in Trivy’s GitHub Actions environment to steal a privileged access token (Aqua Security advisory). With it, they force-pushed 76 version tags in trivy-action, redirecting trusted references to malicious commits (CrowdStrike: From Scanner to Stealer). They then triggered release automation to publish an infected Trivy binary — v0.69.4 — to official channels including GitHub Releases and container registries.

The poisoned Trivy binary was elegant in its design. It ran the legitimate scanner in parallel with a stealer payload, making detection difficult. Under the hood, it dumped CI runner process memory, swept over 50 filesystem paths for credentials (SSH keys, cloud IAM configs, Kubernetes tokens, Docker registry tokens), encrypted everything with AES-256 + RSA-4096, and exfiltrated the data to attacker-controlled infrastructure (Microsoft: Guidance for Detecting the Trivy Compromise). On developer machines, it additionally dropped a persistent Python backdoor.

The Backwater of Trivy

But TeamPCP was not finished, and this is where the true danger of supply chain attacks reveals itself. In the backwater of the Trivy compromise, a cascade of downstream projects became infected.

The credentials harvested from Trivy’s CI/CD access led TeamPCP to LiteLLM’s PyPI publishing token (Snyk: How a Poisoned Security Scanner Became the Key to Backdooring LiteLLM). On March 24, they published two backdoored LiteLLM versions (1.82.7 and 1.82.8) to PyPI, a package downloaded roughly 3.4 million times per day. The LiteLLM payload was a three-stage weapon: first it harvested every credential it could find (cloud, SSH, Kubernetes, databases, cryptocurrency wallets, LLM API keys), then it attempted lateral movement across Kubernetes clusters by deploying privileged pods, and finally it installed a persistent systemd backdoor that polls for additional payloads every 50 minutes (Trend Micro: Inside the LiteLLM Supply Chain Compromise). Version 1.82.8 went further still, installing a .pth file in Python’s site-packages that fires on every Python interpreter startup — no import required (Wiz: TeamPCP Trojanizes LiteLLM).

Checkmarx’s KICS GitHub Action was compromised through the same cascading mechanism (Sysdig: TeamPCP Expands). And the npm ecosystem was hit by a self-propagating worm (“CanisterWorm”) leveraging stolen publish tokens, with a command-and-control infrastructure running on a blockchain-based decentralized network resistant to takedowns (Mend.io: CanisterWorm npm Attack).

This is the pattern we should expect going forward. A single compromised tool that runs in thousands of CI/CD pipelines becomes a skeleton key to every secret those pipelines touch. We will, for the foreseeable future, live with the threat of other popular open-source components being compromised in exactly this way — where one breach cascades outward through the dependency graph of the entire ecosystem.

Why Traditional Defenses Didn’t Help

It is worth being specific about what failed here, because these are controls most organizations consider foundational.

Code review did not catch it. The attacker did not submit a pull request with malicious code. They used compromised credentials to force-push existing version tags to point at new, malicious commits — bypassing the review process entirely. As Wiz’s analysis noted, the attacker redirected “existing, trusted version references to malicious commits,” causing downstream workflows to execute attacker-controlled code without any visible change to release metadata.

Commit signing told part of the story — but nobody was checking. Upwind’s breakdown found that the original legitimate commits were GPG-signed by GitHub’s web-flow key, while the attacker’s replacement commits were unsigned and carried impossible timestamps (claiming dates from 2021–2022 but with parent commits from March 2026). This was a detectable signal — but only if your pipeline explicitly validates signatures and commit metadata, which most do not.

Dependency scanning was irrelevant. The malicious code was injected into the trusted tool itself, not into a new or unexpected dependency. The SBOM was technically accurate — the bill of materials matched — but the materials themselves were poisoned. As SANS Institute observed, “supply chain compromises bypass most preventive controls upstream of the runner.”

Package publishing used legitimate credentials. The LiteLLM backdoor was published to PyPI using the real maintainer’s stolen token. For downstream consumers, this was indistinguishable from a normal release. Snyk’s investigation confirmed the malicious versions were published under the legitimate package maintainer’s account.

These are not failures of implementation. They are structural limitations of controls that operate upstream of execution. Once the attacker has valid credentials and access to the release pipeline, the code that reaches your environment looks exactly like a legitimate update.

Why Runtime Enforcement Matters

When upstream controls fail — and in a supply chain attack, they will — the last line of defense is runtime. When the malicious code actually tries to read a credential file, write a persistence mechanism to disk, or spawn a process it has no business spawning, it has to interact with the operating system. That interaction is where it becomes visible. And where it can be stopped.

bifrost generates tailored AppArmor profiles for every container in your environment by observing legitimate behavior during testing and staging. The resulting profile is a strict allowlist enforced at the kernel level: only the file paths, system calls, process executions, and capabilities that the application actually uses are permitted. Everything else is denied.

Consider what this means for a compromised Trivy binary. A bifrost profile for Trivy would permit reading container image layers and vulnerability databases, writing scan reports, and executing the specific binaries Trivy needs. It would not permit reading ~/.aws/credentials, dumping process memory via /proc/[pid]/mem, writing Python scripts to arbitrary paths, or creating new repositories via API calls. Every file-access and process-execution action in the TeamPCP payload would have been blocked — not because bifrost knew about TeamPCP, but because those actions are simply not things Trivy does.

The same applies to LiteLLM. A profiled LiteLLM container can receive API requests, route to configured LLM providers, and return responses. It cannot read Kubernetes service account tokens, deploy privileged pods, install systemd user services, or write .pth files into site-packages/. The three-stage payload would have been dead on arrival.

Critically, AppArmor profiles are immune to the supply chain compromise itself. The profile is generated from observed behavior in your environment — not from the vendor’s build system, not from package signatures, not from SBOMs. A compromised binary that behaves differently from what was observed during training will be caught, regardless of how it got compromised.

It is worth noting that AppArmor’s strength lies in controlling file access, process execution, and capability usage. For network-level controls — blocking connections to unknown C2 servers, for instance — stricter egress and ingress policies via network policies or firewalls remain the right tool. A layered approach that combines AppArmor for system-level behavior with proper network segmentation provides the most complete protection.

What You Can Do Today

The TeamPCP campaign is ongoing. The threat actor has demonstrated the ability to pivot across ecosystems and has shown a level of persistence and sophistication that suggests this is not the last we will hear from them.

Here is what we recommend:

Audit your exposure. Check if any environment ran Trivy v0.69.4, the compromised trivy-action tags, or LiteLLM versions 1.82.7/1.82.8. Rotate all credentials that were accessible in those environments.

Pin versions and verify integrity. Never reference mutable tags for actions or dependencies. Pin to exact versions and, wherever possible, use SHA-256 digest hashes to verify that the artifact you deploy is byte-for-byte what you intend. For GitHub Actions, this means pinning to commit SHAs rather than version tags — which is exactly the vector TeamPCP exploited. For container images, pin to digest (image@sha256:...) rather than tags.

Use signed packages and verify signatures. Where ecosystems support it (Sigstore/cosign for containers, PGP for npm, PyPI’s Trusted Publishers), enable signature verification in your pipelines. As the Trivy compromise showed, the attacker’s replacement commits lacked the original GPG signatures — a signal that would have been caught by strict verification. This won’t stop every supply chain attack, but it raises the bar significantly.

Enforce strict network egress controls. The TeamPCP payloads exfiltrated data to attacker-controlled domains and polled C2 infrastructure for follow-up payloads. Kubernetes NetworkPolicies, service mesh egress rules, or firewall allowlists that restrict outbound connections to known-good destinations would have disrupted both the data exfiltration and the persistence mechanism.

Monitor for deviations in runtime behavior. Even before you enforce, you need visibility. Deploy runtime monitoring that flags anomalous system calls, unexpected file access patterns, and unusual process executions. A vulnerability scanner suddenly reading SSH keys and writing Python scripts to /usr/local/bin is not normal — and that deviation is detectable before any damage is done.

Profile your security tools first. Scanners, linters, and CI/CD tools are high-value targets precisely because they run with broad access to secrets. They should be the first workloads you wrap in behavioral profiles, not the last.

How bifrost Makes This Automatic

bifrost integrates directly into your CI/CD pipeline and Kubernetes clusters to provide tailored AppArmor profiles — automatically, for both your first-party code and the third-party open-source components you depend on.

For your own services, bifrost’s listener in staging captures the legitimate behavior of each container as your code evolves, generating an up-to-date profile at every deployment. No manual policy authoring, no stale profiles drifting out of sync with your codebase.

For third-party tools like Trivy, LiteLLM, or any open-source component in your stack, the same approach applies. bifrost observes how the tool actually behaves in your environment and generates a profile scoped to that behavior. When a compromised version suddenly starts reading credential files, spawning unexpected processes, or writing persistence mechanisms, those actions fall outside the profile and are blocked at the kernel level — regardless of whether the compromise has been publicly disclosed yet.


bifrost Security provides automated, behavior-based AppArmor profiles for containerized workloads. Learn more at bifrostsec.com or get started.


Tags

container trivy security cve vulnerability compliance

Ready to see runtime security in action?

bifrost automatically generates tailored security profiles for your containers and cuts CVE noise by up to 90%. Free trial, no credit card required.