A malicious litellm 1.107.0 went up on PyPI at 11:39 UTC on October 21, 2026. PyPI quarantined it at 13:20 UTC, and LiteLLM pulled the matching Docker images at 13:53 UTC. Datadog Security Labs published the analysis this post draws on. The maintainers track the incident in BerriAI/litellm issue #47826. The last clean release is 1.106.2.
If you install LiteLLM unpinned, run its proxy from latest or main-stable, or rebuilt a CI image that afternoon, you may have pulled it.
How it got published
The attackers held GitHub CLI OAuth tokens from three LiteLLM engineers. Datadog says it isn't clear yet how they got them. They used those tokens to start LiteLLM's private release workflow against Berri-AI/litellm, a fork whose name differs from the real BerriAI/litellm by one hyphen. They approved the run and deleted the evidence.
The wheels came out of LiteLLM's real pipeline, so they carry build provenance. That provenance names the malicious fork as the source. A provenance check that asks "did LiteLLM's workflow build this?" says yes. A check that pins the source repository to BerriAI/litellm says no.
| Where | What |
|---|---|
| PyPI | litellm==1.107.0, wheels for macOS, manylinux, musllinux and Windows |
| GHCR and Docker Hub | tags v1.107.0, latest, main-latest, main-stable |
| Image index digest | sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e |
Uninstalling won't clean it
The wheel adds three files to site-packages:
cook.pthcook.pysitecustomize.py
Python executes .pth files and sitecustomize.py each time the interpreter starts. The malware runs in that environment even if your code never imports litellm. pip uninstall litellm removes the package directory and leaves these three files in place, and the pip you ran to uninstall starts Python, which runs the malware again.
cook.py collects secrets, encrypts them with AES-256 and RSA-4096, and posts them to www.litellm[.]dev/healthcheck with the header X-Token: XWiA8gZNa7NcX2XRoAEb. The real project lives at litellm.ai. The list of targets covers most of a developer laptop or CI runner:
- cloud credentials for AWS, GCP and Azure, instance metadata included, plus Kubernetes, Docker, Vault and Terraform secrets
- SSH, GPG and TLS keys, Git, npm and PyPI tokens,
.envfiles and shell history - API keys and sessions for Claude, Codex, Gemini, Cursor, Copilot and other AI tools
- saved browser passwords and cookies
- on a LiteLLM proxy with a database, the tables that hold upstream provider keys
sitecustomize.py is a backdoor. Each hour it reads a domain name from a file in a GitHub repository, letters9813/pythonclient-test, then downloads and runs Python from that domain. The repository is gone, and Datadog saw nothing but test values, with no second stage in the wild.
Check a machine or image
# Which version is installed?
python -m pip show litellm 2>/dev/null | grep -i '^version'
# Look for the dropped files without starting the suspect interpreter
find / -path '*site-packages/*' \
\( -name 'cook.pth' -o -name 'cook.py' -o -name 'sitecustomize.py' \) \
2>/dev/null
# Host markers the malware leaves
ls -la /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock 2>/dev/null
The first command starts Python, so run it from a clean interpreter or skip it and read site-packages/litellm-*.dist-info with ls. A sitecustomize.py can belong to your distribution, so read any hit before you delete it. For containers, search your registry and deploy history for the digest above and for any pull of latest or main-stable on October 21.
If you find it
Datadog lists five steps:
- Delete
cook.pth,cook.pyandsitecustomize.pyfromsite-packages. - Remove the 1.107.0 install and anything built from it. Rebuilding the image beats patching it.
- Pin
litellm==1.106.2. - From a different, clean machine, rotate every credential the host could read.
- Audit cloud, Git and provider logs for use of those credentials since 11:39 UTC on October 21.
Step 4 is the expensive one. On a CI runner, "every credential" means the deploy keys, registry tokens and cloud roles that runner holds, along with your model provider keys.
This week
- Search every lockfile, image and CI log for
litellm1.107.0 and for the image digest above. - Pin LiteLLM by version and hash, and pull its images by digest, not by
latestormain-stable. - If you maintain a package, restrict your release workflow to your own repository and protected branches, and treat
ghOAuth tokens on engineers' laptops as production secrets. - If you verify provenance for dependencies, check the source repository field, not the signer alone.
Volodymyr Chornous

