The LiteLLM Supply Chain Attack: What Happened and What It Means
The LiteLLM Supply Chain Attack: What Happened and What It Means
Yesterday (March 24, 2026), threat actor TeamPCP published backdoored versions of the litellm Python package to PyPI. Versions 1.82.7 and 1.82.8 contained a multi-stage credential stealer that harvested API keys, cloud credentials, crypto wallets, and SSH keys from every system that installed them.
LiteLLM averages 3.4 million downloads per day. The malicious versions were live for approximately 3-5 hours before being pulled.
This is not a hypothetical risk. This happened yesterday. Here's exactly what went down.
The Attack Chain
TeamPCP didn't hack LiteLLM directly. They went upstream.
Step 1 — Compromise Trivy (March 19)
Trivy is Aqua Security's open-source vulnerability scanner — used by thousands of CI/CD pipelines worldwide. TeamPCP rewrote 76 of 77 Git tags in the trivy-action GitHub Action repository, injecting malicious code that exfiltrated environment variables from CI runners.
Step 2 — Steal PyPI credentials
LiteLLM's CI/CD pipeline used Trivy without pinned versions. When the pipeline ran with the compromised Trivy action, the attacker's code stole the PYPI_PUBLISH token from the GitHub Actions environment.
Step 3 — Register exfiltration domain (March 23)
The attacker registered litellm.cloud via Spaceship, Inc. — a domain that looks like it could be legitimate infrastructure.
Step 4 — Publish backdoored packages (March 24)
Using the stolen PyPI token, TeamPCP uploaded two malicious versions directly to PyPI, bypassing LiteLLM's normal release process.
What the Malware Did
Two injection methods were used:
| Version | Method | Trigger |
|---|---|---|
| 1.82.7 | Base64-encoded payload in proxy_server.py | import litellm.proxy |
| 1.82.8 | litellm_init.pth file (34,628 bytes) | Any Python startup — no import needed |
Version 1.82.8 is especially dangerous: the .pth file executes on every Python invocation, not just when LiteLLM is imported. If you installed 1.82.8 in a shared environment, every Python script on that machine activated the malware.
Three-stage payload:
-
Credential harvesting — SSH keys, environment variables, AWS/GCP/Azure/Kubernetes credentials, crypto wallets (Bitcoin, Litecoin, Ethereum, Solana), database passwords, SSL private keys, shell history, CI/CD configs, Slack/Discord tokens.
-
Encryption and exfiltration — Everything encrypted with AES-256-CBC + RSA-4096 and sent via HTTP POST to
https://models.litellm.cloud/. -
Persistence — Installed as
sysmon.pysystem service polling a remote endpoint every 50 minutes for commands. On Kubernetes clusters, attempted to deploy privileged pods.
Downstream Impact
This is the part that should scare everyone.
LiteLLM is a transitive dependency of major AI frameworks: Microsoft GraphRAG, Google ADK, DSPy, OpenHands, and CrewAI all pulled the malicious version as an indirect dependency during the exposure window.
If your application depends on any of these frameworks and ran pip install during those 3-5 hours, you may be compromised.
Why This Matters
LiteLLM had 13 CVEs before this attack — including multiple SQL injections (CVE-2024-5225, CVE-2024-4890), remote code execution via eval() (CVE-2024-4889), RCE via callback manipulation (CVE-2024-6825), SSRF allowing API key interception (CVE-2024-6587), and arbitrary file deletion (CVE-2024-4888).
The supply chain attack is the capstone of a pattern: a widely-used Python package with a history of serious vulnerabilities became the vector for one of the largest credential theft operations targeting the AI ecosystem.
How Ryvos Avoids This Entirely
When we built Ryvos, we made a deliberate choice: single static binary, zero runtime dependencies.
No pip, no npm, no package resolution at runtime
Ryvos compiles to one binary. There is no pip install on startup, no node_modules, no package manager running in production. The binary includes everything: the agent loop, all 86+ built-in tools, the web UI, the gateway, every channel adapter.
A .pth file attack like LiteLLM v1.82.8? Impossible — there's no Python runtime to exploit.
Rust's compile-time dependency model
All Rust dependencies are resolved, downloaded, and compiled at build time. The Cargo.lock file pins every dependency to an exact version with a cryptographic hash. If a crate is tampered with between builds, the hash fails and the build aborts.
There is no runtime package resolution. No dynamic imports. No eval(). No callback injection.
Zero transitive Python dependencies
The LiteLLM attack propagated through Python's dependency graph — frameworks that depended on LiteLLM automatically pulled the compromised version. Ryvos has zero Python dependencies. External tools (MCP servers, skills) run as isolated child processes that cannot access the agent's credentials or internal state.
What You Should Do Now
If you use LiteLLM anywhere:
- Check your version —
pip show litellm. If it's 1.82.7 or 1.82.8, you're compromised. - Pin to v1.82.6 or wait for a verified clean release.
- Rotate ALL credentials — every API key, cloud credential, SSH key, and token that existed as an environment variable or config file on the affected system.
- Check for persistence — look for
sysmon.pyservices,/tmp/pglog,/tmp/.pg_statefiles. - Audit your CI/CD — if you use
trivy-action, pin to a specific commit SHA, not a tag.
The Broader Lesson
This attack exploited trust at every level: trust in a security scanner, trust in CI/CD, trust in a package registry, trust in a dependency chain. The attacker didn't need to break any encryption or exploit any zero-day. They just abused the implicit trust that modern software builds on.
The only real defense is a smaller trust surface. Fewer dependencies. Fewer runtime package managers. Fewer implicit trusts.
A single binary with no runtime dependencies isn't just a technical preference. After yesterday, it's a security requirement.
Ryvos is open source, MIT licensed, and compiles to a single static binary. No pip. No npm. No supply chain. Get started →
Sources: