The LiteLLM Compromise: What a Three-Hour Window Reveals About AI Infrastructure Security
On March 24, 2026, a threat actor published two malicious versions of LiteLLM - a Python package downloaded 3.4 million times per day - to PyPI. For approximately three hours, anyone who installed litellm==1.82.7 or litellm==1.82.8 had their SSH keys, cloud credentials, API tokens, Kubernetes secrets, crypto wallets, and environment variables encrypted and exfiltrated to an attacker-controlled server.
The attack was only discovered because the malware had a bug. A sloppy implementation detail caused an exponential fork bomb that crashed the victim's machine, making the compromise visible. As Andrej Karpathy observed, without the malware's own poor quality, it would have gone unnoticed for much longer.
This is a technical analysis of the incident, what it means for AI infrastructure security, and what it reveals about the fragility of the current AI tooling ecosystem.
The Attack Chain
The short version: An attacker compromised Trivy (a security scanner), used it to steal LiteLLM's PyPI publishing credentials from CI/CD, then published poisoned versions of LiteLLM that steal everything on your machine.
The full chain:
| Date | Event |
|---|---|
| Late Feb 2026 | Attacker (TeamPCP) exploits a pull_request_target workflow vulnerability in Trivy's GitHub Actions to steal the aqua-bot credentials |
| Mar 19 | Trivy v0.69.4 GitHub Action tags rewritten to point to a malicious release |
| Mar 23 | Checkmarx KICS GitHub Action compromised; models.litellm.cloud domain registered |
| Mar 24, 10:39 UTC | Malicious litellm 1.82.7 published to PyPI |
| Mar 24, 10:52 UTC | Malicious litellm 1.82.8 published with escalated .pth delivery |
| Mar 24, 11:48 UTC | FutureSearch engineer discovers the malware after it crashes his machine |
| Mar 24, ~12:44 UTC | Attacker uses compromised maintainer account to close the GitHub issue; floods it with 88 bot comments from 73 accounts in 102 seconds |
| Mar 24, ~13:38 UTC | PyPI quarantines the package |
| Mar 24, 15:27 UTC | Compromised versions deleted; all maintainer keys rotated |
Timeline reconstructed from Snyk, FutureSearch, Endor Labs, and GitHub #24512.
The Payload: Three Stages of Compromise
The malware operates in three stages, each worse than the last.
Stage 1: Harvest Everything
The script systematically collects every credential it can find:
- Cloud credentials - AWS (
~/.aws/credentials), GCP (application default credentials), Azure tokens, full IMDSv2 metadata queries including Secrets Manager and SSM Parameter Store - SSH keys - Every private key format: RSA, Ed25519, ECDSA, DSA. Plus
authorized_keys,known_hosts, and SSH config - Kubernetes -
kubeconfig, service account tokens, cluster certificates, admin configs - Environment variables -
printenvcaptures every API key, database URL, and secret loaded in the shell - Git credentials -
.gitconfig,.git-credentials, credential store - Container registries - Docker
config.json(registry auth tokens) - CI/CD -
terraform.tfvars, Jenkinsfile,.gitlab-ci.yml,.travis.yml,.drone.yml - Database credentials - PostgreSQL, MySQL, Redis, LDAP configs
- Crypto wallets - Bitcoin, Ethereum, Solana, Cardano, Monero wallet files and seed phrases
- Shell history - Bash, Zsh, MySQL, psql, Redis CLI history
- SSL/TLS private keys -
/etc/ssl/private/, Let's Encrypt certificates
Stage 2: Encrypt and Exfiltrate
The collected data is encrypted with AES-256-CBC using a random session key, which is itself encrypted with a hardcoded 4096-bit RSA public key. The bundle is POSTed to https://models.litellm.cloud/ - a domain registered one day before the attack, designed to look legitimate alongside LiteLLM's real domain (litellm.ai).
The RSA public key is identical across the Trivy, Checkmarx KICS, and LiteLLM payloads. Wiz researchers confirmed this match across all three operations - the strongest single technical attribution link tying them to the same threat actor.
Stage 3: Persist and Spread
The malware installs a persistent backdoor at ~/.config/sysmon/sysmon.py with a systemd service disguised as "System Telemetry Service." This backdoor polls https://checkmarx.zone/raw every 5 minutes for new payloads.
If a Kubernetes service account token is present, the malware reads all cluster secrets across all namespaces and deploys privileged alpine:latest pods to every node in kube-system, mounting the host filesystem and installing the backdoor on the underlying infrastructure.
This is not a credential stealer that runs once. It's a persistent implant with worm capabilities.
Why .pth Files Are Dangerous
Version 1.82.7 hid the payload inside proxy_server.py - it only executed when the proxy module was imported. Version 1.82.8 escalated to a .pth file, which is fundamentally more dangerous.
Python's .pth files in site-packages/ execute automatically on every interpreter startup. Not when you import litellm. When you run any Python command. pip install, python -c "print('hello')", your IDE's language server, a linter - all trigger the payload.
This is a known design flaw. CPython maintainers have acknowledged the security risk in issue #113659, but no fix has been applied. MITRE tracks it as T1546.018 (Python Startup Hooks).
The .pth file is correctly listed in the wheel's RECORD with a matching hash. pip install --require-hashes passes. Every standard integrity check passes. The malicious content was published using legitimate stolen credentials, not injected after the fact. There is no hash mismatch, no misspelled package name, no suspicious domain in the metadata.
The Discovery: Saved by a Bug
Callum McMahon at FutureSearch was working on his Mac when it became unresponsive. 11,000 processes running, CPU at 100%, htop taking 10+ seconds to load.
The cause: a Cursor MCP plugin had pulled in LiteLLM as a transitive dependency via uvx. The .pth payload spawned a child Python process, which triggered the same .pth file, which spawned another child - an exponential fork bomb. The malware was never designed to do this. It was a bug in the malware itself.
McMahon used Claude Code to root-cause the issue, found the rogue package in his uv cache, reproduced the malware in a container, and published a disclosure blog post within minutes. He reported it to PyPI security (who quarantined the package) and the LiteLLM maintainers.
As McMahon wrote afterward: "There's definitely an irony here about how Simon Willison has been hammering on about the lethal trifecta for almost a year now surrounding MCP servers, yet MCP servers got us via regular old supply chain attacks, no tricking of LLMs required."
The Issue Suppression Campaign
When the community opened GitHub issue #24512, the attackers used the compromised maintainer account to close it as "not planned." Simultaneously, 88 bot comments from 73 previously-compromised developer accounts flooded the issue in a 102-second window with messages like "Worked like a charm, much appreciated" and "This was the answer I was looking for."
The accounts were not newly created - they were real developer accounts compromised in prior operations. Analysis by Rami McCarthy found 76% overlap with the botnet used during the earlier Trivy disclosure.
The community routed around the suppression by opening a parallel tracking issue (#24518) and continuing discussion on Hacker News, which reached 324 points.
Blast Radius
LiteLLM is not a niche library. It's a central piece of AI infrastructure - a unified interface for calling 100+ LLM APIs - used by DSPy, CrewAI, MLflow, OpenHands, Arize Phoenix, and hundreds of other projects. Multiple major projects filed emergency PRs within hours:
| Project | Action |
|---|---|
| DSPy (Stanford) | PR #9498 - pin litellm |
| MLflow | PR #21971 - pin litellm; PR #21996 - disable CI workflows using secrets |
| CrewAI | PR #5040 - decouple from litellm entirely |
| OpenHands | PR #13569 |
| Arize Phoenix | PR #12342 |
The .pth execution mechanism means CI/CD pipelines that ran pip install during those three hours executed the payload during the build step - before any application code ran.
TeamPCP claimed to have stolen data from approximately 500,000 devices, though some sources note many were duplicates.
About TeamPCP
TeamPCP (also identified as PCPcat, Persy_PCP, ShellForce, and DeadCatx3 per Wiz Threat Center) has been active since at least December 2025. The LiteLLM compromise is Phase 09 of an ongoing campaign.
Consistent infrastructure ties all operations together: same RSA key pair, same tpcp.tar.gz bundle naming, same registrar (Spaceship, Inc.) and hosting provider (DEMENIN B.V.) across all domains.
The group has also deployed CanisterWorm - the first observed use of the Internet Computer Protocol (ICP) as a C2 channel, documented by Aikido researchers. ICP canisters cannot be taken down by domain registrars or hosting providers. A component called hackerbot-claw uses an AI agent for automated attack targeting - one of the first documented cases of an AI agent used operationally in a supply chain attack.
What This Means for AI Infrastructure
1. AI tooling is now a confirmed high-value target
The target selection across TeamPCP's campaign is deliberate: Trivy (security scanner), KICS (infrastructure scanner), LiteLLM (AI model router). Each of these tools requires broad credential access by design. LiteLLM specifically stores API keys for multiple LLM providers - a single compromised instance yields credentials for OpenAI, Anthropic, Google, AWS Bedrock, and potentially every AI provider an organization uses.
This isn't theoretical anymore. The AI infrastructure layer - the gateways, routers, and proxies that sit between applications and LLM providers - is a confirmed high-value target for supply chain attacks.
2. Pass-through credentials are an architectural risk
LiteLLM's architecture requires users to provide their LLM provider API keys, which it stores in environment variables or config files. When the supply chain is compromised, every provider credential is compromised in a single operation.
Any AI gateway or proxy that handles provider credentials faces this same risk. The question isn't whether you handle credentials - it's how they're isolated, how the supply chain is secured, and what happens when a dependency is compromised.
3. The MCP auto-install pattern is dangerous
The victim was infected because a Cursor MCP plugin pulled LiteLLM as a transitive dependency via uvx, which automatically downloads and runs dependencies. The user never explicitly installed LiteLLM. They never ran pip install litellm. A tool in their IDE pulled it in silently.
This is the "seamless ergonomics" of modern AI tooling working against us. The same frictionless install experience that makes tools easy to adopt also makes them easy to weaponize.
4. Security scanners themselves are attack vectors
The deepest irony of this incident: the attack started by compromising Trivy - a security vulnerability scanner. The tool organizations use to check for vulnerabilities in their dependencies was itself the vector that compromised those dependencies.
This is not a one-off. Checkmarx KICS (another security tool) was compromised in the same campaign. The attackers specifically targeted security infrastructure because it has the broadest access and the deepest trust.
5. Runtime security isn't the whole picture
We spend a lot of time thinking about prompt injection, jailbreaks, and output safety. Those threats are real. But if the code processing your prompts is itself compromised, none of that matters. The supply chain is part of the threat model.
Defense in depth means securing the entire pipeline: the code, the dependencies, the CI/CD, the credentials, and the runtime.
If You're Affected
Check your installed version:
pip show litellm 2>/dev/null | grep VersionIf you see 1.82.7 or 1.82.8, treat the system as compromised. Do not just upgrade - the payload has already run.
Check for persistence:
ls -la ~/.config/sysmon/sysmon.py 2>/dev/null && echo "BACKDOOR FOUND"
ls -la ~/.config/systemd/user/sysmon.service 2>/dev/null && echo "PERSISTENCE SERVICE FOUND"Check Kubernetes:
kubectl get pods -A 2>/dev/null | grep "node-setup-"Check for the .pth file:
find $(python3 -c "import site; print(' '.join(site.getsitepackages()))") \
-name "litellm_init.pth" 2>/dev/nullIf affected:
- Remove the package and purge caches (
pip cache purgeorrm -rf ~/.cache/uv) - Remove persistence artifacts (
~/.config/sysmon/,~/.config/systemd/user/sysmon.service) - Rotate every credential that existed on the machine: SSH keys, cloud credentials, API keys, database passwords, Docker registry tokens
- Audit Kubernetes clusters for
node-setup-*pods - Pin to
litellm<=1.82.6in all environments
Indicators of Compromise
File hashes (SHA-256):
| File | Hash |
|---|---|
litellm_init.pth (1.82.8) | 71e35aef03099cd1f2d6446734273025a163597de93912df321ef118bf135238 |
proxy_server.py (1.82.7) | a0d229be8efcb2f9135e2ad55ba275b76ddcfeb55fa4370e0a522a5bdee0120b |
sysmon.py (backdoor) | 6cf223aea68b0e8031ff68251e30b6017a0513fe152e235c26f248ba1e15c92a |
Network indicators:
- Exfiltration:
https://models.litellm.cloud/(POST) - C2 polling:
https://checkmarx.zone/raw(GET)
Filesystem indicators:
~/.config/sysmon/sysmon.pyor/root/.config/sysmon/sysmon.py~/.config/systemd/user/sysmon.service(description: "System Telemetry Service")/tmp/tpcp.tar.gz,/tmp/session.key,/tmp/payload.enc,/tmp/session.key.enc
Kubernetes indicators:
- Pods:
node-setup-{node_name}inkube-system - Container name:
setup, image:alpine:latest
This analysis draws on reporting from Snyk, FutureSearch, FutureSearch postmortem, Endor Labs, Wiz, BleepingComputer, The Register, JFrog, Aikido, and the community discussion in GitHub #24512.
Continue Reading
We Benchmarked Our Detection Engine Against 2,369 Samples from 7 Peer-Reviewed Datasets. Here Are the Results.
PromptGuard's multi-layered detection achieves F1 = 0.887 with 99.1% precision across TensorTrust (ICLR 2024), In-the-Wild Jailbreaks (ACM CCS 2024), JailbreakBench (NeurIPS 2024), XSTest (NAACL 2024), and more — with 100% evasion robustness where standalone classifiers achieve only 80%.
Read more Security ResearchOpenClaw Has 250K Stars and 3 Critical CVEs. Here's How to Secure It.
OpenClaw is the fastest-growing AI agent framework in history, but its local-first, multi-channel architecture creates a massive attack surface. We break down the CVEs, explain the risks, and show how PromptGuard closes the gaps.
Read more EngineeringOne MCP Server to Secure Every AI Tool
PromptGuard's MCP server works with Cursor, Claude, VS Code Copilot, Windsurf, Cline, Roo Code, Continue, Zed, Goose, Lovable, and every other MCP-compatible tool. Here's how one install protects everything.
Read more