Skip to main content

How to Check If You Installed Compromised LiteLLM 1.107.0

How to check if you installed compromised LiteLLM 1.107.0 from PyPI or Docker: a 60-second detection script, the cook.pth startup trick, and what to rotate.

• • 7 min read
Dashboard-style cover showing the LiteLLM 1.107.0 PyPI compromise: three injected files, a startup hook, and a credential stealer

TL;DR Here is how to check if you installed compromised LiteLLM: look for cook.pth, cook.py and sitecustomize.py in site-packages and for /tmp/.pc_once_72129118c59f5636c0bb. Version 1.107.0 was live on PyPI for under two hours on 2026-10-21 and stole cloud, CI and LLM provider credentials in every Python process, not just ones importing LiteLLM. If any indicator hits, rebuild the environment and rotate credentials before you do anything else.

What Is the LiteLLM 1.107.0 PyPI Compromise?

It is a supply-chain attack where a malicious litellm==1.107.0 was built and published through LiteLLM’s own release pipeline, so it carried a legitimate-looking release. SafeDep’s analysis shows the build line data = "cook" was added under [tool.maturin] in the sdist’s pyproject.toml. No public commit in BerriAI/litellm contains it. The wheel therefore ships a cook/ folder that lands three files in site-packages.

ArtifactAffectedNot affected (per SafeDep)
PyPIlitellm==1.107.0 (all seven wheels, plus the sdist)1.106.2, 1.107.0rc1, 1.107.0rc2
Dockerv1.107.0, latest, main-latest, main-stable (11:46-14:20 UTC)Tags after the 14:20 UTC cleanup
CompanionsNonelitellm-proxy-extras 0.4.110, litellm-enterprise 0.1.78

Timeline of the LiteLLM compromise on 2026-10-21 UTC: workflow changed at 10:08, wheels uploaded at 11:39, PyPI removal at 13:23, Docker tags cleaned at 14:20

How Does the Malware Run Without an Import?

Python’s site module executes any line in a .pth file that starts with import, and imports sitecustomize at startup (Python docs). The attacker used both:

  1. cook.pth contains import cook, so cook.py (about 61 KB, base64 and zlib wrapped) runs in every interpreter launch.
  2. cook.py collects SSH keys, shell history, AWS/Azure/GCP/Kubernetes/Docker credentials, CI/CD secrets, AI tool tokens, browser data, environment variables and GPG/TLS keys. On a proxy host it also reads LiteLLM_CredentialsTable and LiteLLM_ProxyModelTable, which hold provider API keys.
  3. Results are AES-256-CBC encrypted, the key is RSA-OAEP wrapped, and the archive is POSTed to www.litellm[.]dev/healthcheck.
  4. sitecustomize.py forks a detached daemon, reads a domain from a GitHub dead-drop, and every hour downloads and exec()s a second stage from /codepy.

Execution chain: pip install drops cook.pth, Python startup imports cook.py which steals credentials, and sitecustomize.py starts an hourly daemon that runs a second stage

SafeDep observed the dead-drop GitHub account returning 404 at 13:40 UTC, so the backdoor currently finds no server. Hosts that ran it earlier may already have executed second-stage code, which SafeDep could not recover.

How to Check If You Installed Compromised LiteLLM

Run this on every laptop, CI runner and container that could have resolved litellm between 11:39 UTC on 2026-10-21 and the removal at 13:23 UTC, or pulled the Docker tags before 14:20 UTC.

  1. Find the injected files in every Python environment:
Bash
for sp in $(python3 -c "import site,sys;print('\n'.join(site.getsitepackages()+[site.getusersitepackages()]))"); do
  ls -l "$sp"/cook.pth "$sp"/cook.py "$sp"/sitecustomize.py 2>/dev/null
done
find / -name cook.pth -not -path "*/proc/*" 2>/dev/null
  1. Compare hashes. On Linux/macOS, cook.pth is 7f191632e732…2bdb, cook.py is 9dd0a3926f96…be25 and sitecustomize.py is 34bef04fe88a…05fa (full SHA-256 values are in the SafeDep post). A sitecustomize.py you did not write is suspicious even if the hash differs.
  2. Check host markers: ls /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock. The first means the stealer uploaded; the second means the backdoor daemon ran.
  3. Look for a detached Python process: ps -eo pid,ppid,sid,cmd | awk '$2==1 && /python/'.
  4. Search egress and DNS logs for www.litellm.dev, and for Python processes calling 169.254.169.254.
  5. Check lockfiles and image history: grep -rn "litellm==1.107.0\|litellm-1.107.0" . and docker history on anything built from the affected tags.
IndicatorMeaning
cook.pth presentStealer ran at every Python start
.pc_once_* marker in /tmpCredentials were uploaded
remote_code_loader.lock in /tmpBackdoor daemon started
Traffic to www.litellm.devExfiltration attempted

What Should You Rotate After a Compromised LiteLLM Install?

SafeDep’s article does not prescribe remediation; this order is my inference from its list of targeted data. Work by blast radius, and rotate from a clean machine.

  1. Cloud and CI/CD: AWS/Azure/GCP keys, Kubernetes configs, Terraform, Vault and runner tokens. Revoke sessions, not just keys.
  2. LLM provider keys: anything in the LiteLLM proxy database, plus keys in .env files and environment variables.
  3. Source control: GitHub CLI tokens, SSH keys, GPG keys.
  4. AI tooling: Claude, Cursor, Copilot and Codex tokens.
  5. Rebuild: delete the virtualenv or image; do not patch in place. Pin to 1.106.2 or a newer, verified release.

How to Stop the Next One

The pattern repeats: axios on npm and mathmain’s encrypted loader used different tricks, same gap. Install-time code runs with your full privileges. Three changes cut most of the risk:

  • Pin with hashes (pip install --require-hashes) and add a cooldown of a few days before adopting new releases.
  • Run agents, CI and proxies in a sandbox with no default internet access; a stealer with nowhere to POST fails quietly. See also stopping agent sandbox escapes.
  • Keep provider keys out of long-lived environment variables. A gateway that holds every key is the richest target in your LLM stack.

If you run agent tooling, the same blast-radius thinking applies to MCP servers and the Claude Code leak fallout.

FAQ

Which LiteLLM versions are compromised? Only 1.107.0 on PyPI and the Docker tags v1.107.0, latest, main-latest and main-stable during 11:46-14:20 UTC on 2026-10-21.

Am I safe if I never imported litellm? No. cook.pth runs at interpreter startup, so every Python process in that environment executed the stealer.

Does pip uninstall litellm clean it up? Not reliably. Rebuild the environment and treat the host as compromised if any indicator is present.

Sources

Frequently asked questions

Share this article:
X LinkedIn

Google Search · Preferred sources

Prefer this site on Google

If you already read this writing, add umesh-malik.com as a Preferred Source. Google can then highlight it with a preferred badge in Top Stories, AI Overviews, and AI Mode — for you, not as a site-wide ranking boost.

Keep reading

Get new posts on AI, Claude Code & LLMs

New deep-dives on AI engineering, Claude Code, and developer tooling — follow along however you prefer.