If you run LiteLLM in production, you probably had a rough week.
On March 24, 2026, two backdoored versions of litellm (1.82.7 and 1.82.8) were published to PyPI using stolen credentials. The malware stole SSH keys, AWS/GCP/Azure credentials, Kubernetes secrets, cryptocurrency wallets, and deployed persistent backdoors on infected machines. It was live for about 3 hours. LiteLLM gets 3.4 million daily downloads.
This is the full breakdown of what happened, why it matters, and what you should actually do about it.
What Happened: The Full Attack Chain
The attack didn't start with LiteLLM. It started with Trivy, a popular container security scanner.
Here's the sequence:
- A threat actor group called TeamPCP exploited a
pull_request_targetworkflow vulnerability in Trivy's GitHub Action (GHSA-9p44-j4g5-cfx5) - They used this to exfiltrate the aqua-bot credentials and rewrite Trivy v0.69.4 release tags to point to malicious payloads
- On March 23, they also compromised the Checkmarx KICS GitHub Action using similar techniques
- LiteLLM's CI/CD pipeline pulled the Trivy action without pinning to a specific version or commit SHA
- The malicious Trivy action exfiltrated LiteLLM's
PYPI_PUBLISHtoken from the GitHub Actions runner - Using the stolen token, TeamPCP published two backdoored versions to PyPI with legitimate credentials
The full timeline is documented in Snyk's breakdown and Wiz's attribution analysis.
The Malware: Three Stages of Damage
This was not a simple credential stealer. It was a three-stage payload designed for maximum extraction and persistence.
Stage 1: Information Collection
The malware harvested:
- System data (hostname, environment variables, processes, network routing, auth logs)
- SSH private keys,
.envfiles, Git credentials - API keys from shell history
- Slack and Discord webhook tokens
- Jenkins, Travis CI, and Terraform configs
-
/etc/shadowpassword hashes - Full AWS credential chain including IMDSv2, Secrets Manager, and SSM Parameter Store
- GCP and Azure service account files
- Docker
config.jsonand Kubernetes kubeconfig, service account tokens, secrets, and certificates - Cryptocurrency wallet files (Bitcoin, Ethereum, Solana, Cardano, Monero, Ledger hardware wallet configs)
Stage 2: Encryption and Exfiltration
Everything was bundled, encrypted with AES-256-CBC, the session key wrapped with a hardcoded 4096-bit RSA public key, and exfiltrated to models.litellm.cloud, a domain registered just one day before the attack.
Stage 3: Persistence and Lateral Movement
The malware installed a persistent backdoor at ~/.config/sysmon/sysmon.py with a systemd service polling checkmarx.zone every 5 minutes for new payloads. In Kubernetes environments, it read all secrets across every namespace and deployed privileged pods to every kube-system node, mounting the host filesystem.
Source: Snyk's full technical analysis
Two Delivery Mechanisms (This Is the Scary Part)
Version 1.82.7 embedded a Base64-encoded payload directly in litellm/proxy/proxy_server.py. It executed whenever anything imported litellm.proxy.
Version 1.82.8 added something worse: a file called litellm_init.pth placed in site-packages/. Python's .pth mechanism fires on every interpreter startup. That means the malware ran when you ran pip install, when your IDE started a language server, when you ran python -c "print('hello')". It had nothing to do with importing litellm.
This is MITRE ATT&CK T1546.018 (Python Startup Hooks). The .pth file was correctly declared in the wheel's RECORD file, so pip install --require-hashes would have passed.
Who Was Affected
The compromised versions were pulled into multiple major projects:
| Project | PR Merged | Status |
|---|---|---|
| DSPy | #9498 | Affected |
| MLflow | #21971 | Affected |
| OpenHands | #13569 | Affected |
| CrewAI | #5040 | Affected |
| Arize Phoenix | #12342 | Affected |
| Aider | N/A | Safe (pinned litellm==1.82.3) |
Aider survived because it pinned its dependency version. That one decision made the difference.
How Standard Defenses Failed
This attack bypassed almost every standard protection:
- Hash verification passed because the packages were published with legitimate stolen credentials
-
No typosquatting to detect. The package name was exactly
litellm -
No suspicious domains at install time. The exfiltration domain was
models.litellm.cloud, which looks legitimate -
pip install --require-hasheswould have passed because the.pthfile was correctly declared in the wheel's RECORD
The only install-time defense that would have caught this is inspecting whether packages install .pth files containing subprocess, base64, or exec patterns. No widely deployed pip plugin does this automatically today.
The Bot Suppression Campaign
When researcher Callum McMahon at FutureSearch reported the compromise in GitHub issue #24512, TeamPCP used 73 previously compromised GitHub accounts to post 88 spam comments in 102 seconds, then closed the issue as "not planned" using the compromised maintainer account krrishdholakia.
76% of these accounts overlapped with the botnet used during the Trivy disclosure. This is documented in Wiz's analysis.
The Structural Problem Nobody Is Talking About
LiteLLM is a Python package. It sits between your application and your LLM providers. It holds API keys for OpenAI, Anthropic, AWS Bedrock, Google Vertex, and whatever else you route through it. It is, by design, a high-value target.
And it runs in a language where:
- Any package can install
.pthfiles that execute on interpreter startup - Transitive dependencies pull in dozens of packages you never explicitly chose
- A single compromised CI/CD token can publish arbitrary code under a trusted package name
- The GIL means you need to run multiple processes, each of which triggers
.pthexecution independently
This is not a criticism of Python as a language. Python is excellent for what it is good at. But the question is whether Python is the right choice for infrastructure that holds your most sensitive credentials and sits in the critical path of every LLM request.
Compiled languages like Go and Rust produce single binaries with no runtime dependency chain. There is no site-packages directory. There is no .pth execution mechanism. There is no pip install side effect. The attack surface is fundamentally smaller.
What You Should Do Right Now
1. Check Your LiteLLM Version
pip show litellm | grep Version
If you see 1.82.7 or 1.82.8, you were affected. LiteLLM's security update confirms these versions were compromised.
2. Scan for .pth Files
find $(python -c "import site; print(site.getsitepackages()[0])") -name "*.pth" -exec grep -l "subprocess\|base64\|exec" {} \;
3. Rotate Everything
If you ran the compromised version, assume all credentials on that machine are compromised:
- AWS/GCP/Azure keys and service accounts
- SSH keys
- API keys (OpenAI, Anthropic, etc.)
- Database passwords
- Kubernetes service account tokens
- CI/CD tokens
4. Pin Your Dependencies
Aider survived because it pinned litellm==1.82.3. Pin your versions. Better yet, pin by hash:
litellm==1.82.6 --hash=sha256:<known-good-hash>
5. Pin Your CI/CD Actions by SHA
Don't do this:
uses: aquasecurity/trivy-action@latest
Do this:
uses: aquasecurity/trivy-action@<full-commit-sha>
6. Evaluate Your Gateway Architecture
This is the harder conversation. If your LLM gateway is a Python package that you pip install, it shares the same supply chain as every other Python package on your system. Every transitive dependency is a potential attack vector.
Alternatives worth evaluating:
- Bifrost: Open-source LLM gateway written in Go. Single compiled binary, 11 microsecond overhead at 5,000 RPS. No Python supply chain surface area. Supports OpenAI, Anthropic, Bedrock, Vertex, and 20+ providers.
- TensorZero: Rust-based LLM gateway with sub-millisecond overhead. Similar compiled-binary benefits.
- Cloudflare AI Gateway: Managed edge service. No self-hosted dependency chain at all.
- Direct provider SDKs: If you only use one or two providers, you may not need a gateway at all. The official OpenAI and Anthropic SDKs are smaller attack surfaces.
The right choice depends on your scale, provider count, and security requirements. But "keep using the Python package that just got backdoored" should not be the default.
The Bigger Picture
TeamPCP is not done. They also deployed CanisterWorm, using the Internet Computer Protocol as a C2 channel. They used an AI agent called openclaw for automated attack targeting. Their target selection focuses on tools with elevated pipeline access: container scanners, infrastructure scanning tools, AI routing libraries.
LLM gateways are a perfect target. They hold credentials for multiple providers. They run in CI/CD environments. They have broad read access by design.
The question is not whether this will happen again. It is whether your infrastructure is designed to limit the blast radius when it does.
References:
- Snyk: How a Poisoned Security Scanner Became the Key to Backdooring LiteLLM
- FutureSearch: Supply Chain Attack in litellm 1.82.8 on PyPI
- Wiz: TeamPCP Trojanizes LiteLLM
- LiteLLM Security Update: March 2026
- GitHub Issue #24512
- The Register: LiteLLM infected via Trivy compromise
- Microsoft: Detecting the Trivy Supply Chain Compromise
- Kaspersky: Trojanization of Trivy, Checkmarx, and LiteLLM
Tags: litellm, supply-chain-attack, security, python, llm-gateway, ai-infrastructure, devops, cybersecurity
Top comments (0)