← Back to all articles

LiteLLM Supply Chain Attack: What MSPs Need to Know

Analysis of the TeamPCP supply chain attack on LiteLLM via compromised Trivy GitHub Actions, covering the 3-layer payload, IOCs, and defensive actions for MSPs.

Updated 11 min read

On March 24, 2026, two malicious versions of LiteLLM were published to PyPI. Versions 1.82.7 and 1.82.8 contained a multi-stage credential stealer that harvested cloud credentials, SSH keys, Kubernetes configs, and cryptocurrency wallet data from every system that installed them. The exposure window was roughly 2 to 5 hours, but with approximately 3.4 million daily downloads, the blast radius was significant.

This was not a vulnerability in LiteLLM’s code. It was the result of a cascading supply chain attack by a threat actor known as TeamPCP, who pivoted through Aqua Security’s compromised Trivy GitHub Actions to reach LiteLLM’s CI/CD pipeline. This post covers the full attack chain, the 3-layer payload architecture, indicators of compromise, and what you should check in your environments.

Timeline of events

DateEvent
March 1Initial TeamPCP supply chain campaign begins targeting developer infrastructure
March 19Aqua Security’s Trivy GitHub Actions compromised; attacker force-pushes 76 of 77 release tags to malicious commits
March 23Checkmarx KICS GitHub Actions and VS Code extensions compromised via the same campaign
March 24LiteLLM v1.82.7 and v1.82.8 published to PyPI with malicious payload (10:39 to 16:00 UTC)
March 25Callum McMahon (FutureSearch) discovers the payload after it causes system degradation; GitGuardian publishes analysis
March 26LiteLLM team adds indicators of compromise to their security advisory

The entire chain, from the initial Trivy compromise on March 19 to malicious PyPI packages on March 24, took five days. LiteLLM was a downstream casualty, not the original target.

How the attack chain worked

The attack exploited trust relationships between open-source security tooling and CI/CD infrastructure. Here is the full chain as documented by Trend Micro and GitGuardian.

Step 1: Exploiting pull_request_target in Trivy. Aqua Security’s Trivy repository used a GitHub Actions workflow triggered by pull_request_target. This trigger runs in the context of the base repository (not the fork), which means it has access to repository secrets. The attacker, operating under the GitHub handle MegaGame10418, submitted a pull request that exploited this misconfiguration to exfiltrate the aqua-bot Personal Access Token.

Step 2: Force-pushing release tags. With the stolen PAT, the attacker force-pushed 76 of 77 release tags in the trivy-action repository to point at malicious commits. They similarly compromised all seven tags in the setup-trivy repository. Any CI/CD pipeline referencing these actions by tag (rather than by commit SHA) would now pull attacker-controlled code.

Step 3: LiteLLM’s CI/CD runs the compromised scanner. LiteLLM’s pipeline referenced Trivy by tag for security scanning. When it ran, the compromised Trivy action executed in LiteLLM’s CI/CD environment and exfiltrated the environment’s secrets, including a PyPI publish token and a GitHub Personal Access Token.

Step 4: Publishing malicious packages. The attacker used the stolen PyPI token to publish versions 1.82.7 and 1.82.8 with embedded credential-stealing malware. The stolen GitHub PAT was used to deface the maintainer’s profile and modify personal repositories.

graph TD
  A["Trivy Scanner Compromised<br/><small>pull_request_target exploit on GitHub Actions</small>"] --> B["Release Tags Force-Pushed<br/><small>76 of 77 trivy-action tags replaced</small>"]
  B --> C["LiteLLM CI/CD Executes Trivy<br/><small>Compromised scanner runs in pipeline</small>"]
  C --> D["CI/CD Secrets Exfiltrated<br/><small>PyPI publish token + GitHub PAT stolen</small>"]
  D --> E["Malicious PyPI Publish<br/><small>v1.82.7 and v1.82.8 with credential stealer</small>"]
  D --> F["GitHub PAT Abused<br/><small>Maintainer profile defaced, repos modified</small>"]
  E --> G["Downstream Installations<br/><small>~3.4M daily downloads exposed</small>"]
  style A fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style B fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style C fill:#92400e,stroke:#78350f,color:#fef3c7
  style D fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style E fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style F fill:#5b21b6,stroke:#4c1d95,color:#ede9fe
  style G fill:#5b21b6,stroke:#4c1d95,color:#ede9fe

The critical failure was not just the misconfiguration. Aqua Security’s remediation after the initial compromise on March 1 was, as Trend Micro described it, “not atomic.” There was a multi-day window during credential rotation where the attacker retained valid credentials. That gap enabled the March 19 force-push attack and everything that followed.

The 3-layer payload

The malicious code embedded in versions 1.82.7 and 1.82.8 was not a simple backdoor. It was a structured, 3-layer attack designed for maximum credential extraction and long-term persistence, as analyzed by Ox Security and BleepingComputer.

graph TD
  INSTALL["pip install litellm==1.82.7 or 1.82.8<br/><small>Malicious package installed</small>"] --> L1
  L1["Layer 1: Encrypted Launcher<br/><small>AES-256-CBC payload, RSA key wrapping</small>"] --> L2
  L2["Layer 2: Credential Harvester<br/><small>Comprehensive system enumeration</small>"] --> TARGETS
  L2 --> L3["Layer 3: Persistence<br/><small>systemd service + C2 polling</small>"]
  TARGETS["SSH Keys / Git Credentials<br/>AWS / GCP / Azure Credentials<br/>Kubernetes Configs / DB Passwords<br/>Crypto Wallets / TLS Private Keys"]
  TARGETS --> EXFIL["Encrypted Exfiltration<br/><small>tpcp.tar.gz sent to models.litellm.cloud</small>"]
  L3 --> BACKDOOR["Backdoor: ~/.config/sysmon/sysmon.py<br/><small>Polls checkmarx.zone every 50 minutes</small>"]
  style INSTALL fill:#92400e,stroke:#78350f,color:#fef3c7
  style L1 fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style L2 fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style TARGETS fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style EXFIL fill:#991b1b,stroke:#7f1d1d,color:#fef2f2
  style L3 fill:#5b21b6,stroke:#4c1d95,color:#ede9fe
  style BACKDOOR fill:#5b21b6,stroke:#4c1d95,color:#ede9fe

Layer 1 (Launcher): The initial code decrypts an embedded payload using AES-256-CBC. The session key is wrapped with an RSA public key hardcoded in the package, meaning only the attacker can decrypt captured data. The decrypted payload bootstraps the next two layers.

Layer 2 (Credential Harvester): The harvester performs comprehensive system enumeration, targeting:

  • SSH keys and configurations from ~/.ssh/
  • Git credentials from ~/.git/config and credential stores
  • Cloud provider credentials: AWS IAM keys and temporary tokens, GCP service account keys, Azure connection strings and service principals
  • Kubernetes configuration files and service account tokens
  • Database credentials from environment files and configuration directories
  • Cryptocurrency wallet data, including private keys
  • TLS private keys from system certificate stores

The harvester did not just collect stored credentials. It actively used discovered credentials to query cloud APIs and access Kubernetes secrets, amplifying the impact beyond what was stored on disk. All collected data was encrypted and packaged into a tpcp.tar.gz archive, then exfiltrated to models.litellm.cloud.

Layer 3 (Persistence): The malware installed a systemd user service disguised as “System Telemetry Service” and wrote a backdoor to ~/.config/sysmon/sysmon.py. This backdoor polled checkmarx.zone every 50 minutes for additional payload downloads. On Kubernetes clusters, the malware deployed privileged pods named node-setup-* to maintain access.

Why v1.82.8 was more dangerous

The .pth file mechanism in v1.82.8 deserves special attention because its blast radius extends far beyond LiteLLM usage.

Python loads .pth files from site-packages during interpreter initialization, before any user code runs. This means v1.82.8’s payload executed on every Python process on the infected system: web servers, data pipelines, CI/CD runners, developer tools, Jupyter notebooks, anything using the same Python installation.

For MSPs managing client environments with Python workloads, this distinction matters. A developer workstation that installed v1.82.8 would execute the malware every time any Python script ran, even if that script had nothing to do with LiteLLM. The same applies to CI/CD runners, production servers running Django or Flask applications, and any containerized Python workload sharing the same base image.

Package removal alone did not clean up the .pth file. Systems that installed v1.82.8 required manual inspection of site-packages for litellm_init.pth and verification that the persistence mechanisms (systemd service, sysmon.py backdoor) were also removed.

Indicators of compromise

If any system in your environment installed LiteLLM between March 24 10:39 UTC and 16:00 UTC, check for these artifacts.

Command and control infrastructure:

  • models.litellm.cloud (primary exfiltration endpoint)
  • checkmarx.zone / 83.142.209.11 (payload download, C2 polling)
  • scan.aquasecurity.org / 45.148.10.212

Filesystem artifacts:

  • ~/.config/sysmon/sysmon.py (backdoor)
  • litellm_init.pth in any site-packages directory (v1.82.8 persistence)
  • /tmp/pglog and /tmp/.pg_state (temporary staging files)
  • tpcp.tar.gz (encrypted exfiltration archive)

Kubernetes indicators:

  • Privileged pods named node-setup-* that were not created by your team
  • Unauthorized service accounts created after March 24

Systemd persistence:

  • User service named “System Telemetry Service”

What to do now

Immediate: check for exposure

  • Verify whether any system installed LiteLLM v1.82.7 or v1.82.8 between March 24 10:39 UTC and 16:00 UTC. Check pip freeze output, requirements.txt history, Docker image layers, and CI/CD build logs.
  • Search for the filesystem artifacts listed above on all potentially affected hosts
  • Review DNS logs for connections to the three C2 domains
  • Inspect Kubernetes clusters for node-setup-* pods or unauthorized service accounts
  • Check AWS CloudTrail, GCP Audit Logs, and Azure Activity Log for unexpected API calls from affected systems

Short-term: contain and remediate

  • If any IOCs are found, treat the host as fully compromised. The credential harvester was comprehensive, and the malware actively used discovered credentials to probe cloud APIs and Kubernetes secrets.
  • Rotate all credentials that were present on affected systems: SSH keys, cloud provider access keys, database passwords, API tokens, and any secrets stored in environment variables or configuration files
  • Revoke and reissue TLS certificates whose private keys were on affected hosts
  • Remove litellm_init.pth from all site-packages directories and delete ~/.config/sysmon/ entirely
  • Pin LiteLLM to v1.82.6 or earlier (confirmed safe) and verify package checksums
  • Rebuild Docker images from scratch with clean dependencies rather than patching existing containers

Ongoing: harden your supply chain

  • Pin GitHub Actions to commit SHAs, not mutable version tags. This single change would have prevented the Trivy tag-replacement attack from propagating downstream.
  • Scope PyPI tokens to specific packages using Trusted Publishers where possible
  • Enable pip --require-hashes for production deployments to verify package integrity
  • Audit all CI/CD workflows for pull_request_target usage and ensure they do not expose secrets to untrusted code
  • Implement artifact verification using Sigstore or cosign where available
  • Subscribe to security advisories for your critical dependencies

The bigger picture for MSPs

LiteLLM is an open-source AI gateway that provides a unified interface for calling multiple LLM providers (OpenAI, Anthropic, Cohere, Azure, and others) through a single API. It typically sits directly between applications and AI service providers, which means it has access to API keys and configuration for every connected model.

That positioning made it a high-value target. Compromising LiteLLM potentially exposed not just the host system’s credentials, but every AI provider API key routed through it.

For MSPs, this incident reinforces several realities:

AI tooling is now a supply chain risk. As AI integration accelerates across client environments, packages like LiteLLM, LangChain, and similar middleware become critical infrastructure components. LiteLLM sits between applications and multiple AI providers, so a single compromise exposed API keys for every connected model. These packages need the same dependency governance and monitoring as your core application frameworks.

Your CI/CD trust chain is only as strong as its weakest dependency. The attacker never found a code bug in LiteLLM. They exploited a misconfigured GitHub Actions trigger in Trivy, used the stolen credentials to compromise release tags, and pivoted through the CI/CD trust chain to reach the PyPI publishing token. Every link in that chain was a legitimate trust relationship operating as designed.

Speed of detection determines blast radius. Two to five hours of availability on a package with 3.4 million daily downloads means hundreds of thousands of potentially affected installations. Automated dependency monitoring and rapid incident response are the difference between a contained event and a full credential rotation across your client base.

Key takeaways

  • Pin GitHub Actions to commit SHAs, not version tags. This single change would have broken the attack chain. Mutable tags allowed the attacker to silently replace Trivy with a malicious version. If you maintain CI/CD pipelines, audit this today.
  • The .pth persistence mechanism is system-wide. Version 1.82.8 did not just compromise LiteLLM processes. It installed a hook that runs on every Python interpreter startup, turning the entire system into a backdoor regardless of what code is actually running.
  • Package removal is not sufficient remediation. The .pth file, systemd service, and sysmon.py backdoor all persist after uninstalling LiteLLM. Systems that installed the affected versions require manual IOC sweeps and, if compromised, full credential rotation.
  • Treat AI middleware as critical infrastructure. LiteLLM had access to every API key routed through it. As AI tooling becomes embedded in client environments, apply the same supply chain governance you would to your core frameworks.
  • Non-atomic credential rotation creates attack windows. Aqua Security’s remediation after the initial Trivy compromise left a multi-day gap where the attacker retained valid credentials. When rotating secrets after an incident, ensure the rotation is complete and immediate.

Huntress 2026 Cyber Threat Report: Key Findings for MSPs

Analysis of the Huntress 2026 Cyber Threat Report covering identity compromise, RMM abuse, ClickFix loaders, ransomware timelines, and a 30-day action plan.

Huntress Blocks Device Code Phishing from Railway

Huntress deployed a conditional access policy across ITDR-protected tenants to block device code phishing from Railway infrastructure using AI-generated lures.

Search articles
esc to close