On October 21, 2026, attackers published a malicious LiteLLM 1.107.0 to PyPI and Docker that steals credentials and installs a remote code loader, and it runs every time Python starts, not only when your code imports LiteLLM. LiteLLM says every earlier version is safe and recommends pinning litellm==1.106.2. If any machine installed 1.107.0, or ran the affected Docker tags, during the exposure window, treat it as compromised: clean or rebuild it, then rotate every secret it could reach.
LiteLLM is a popular open-source Python library and proxy that puts many AI model providers behind one OpenAI-style API, so the machines that run it tend to hold exactly the keys an attacker wants. This guide covers who is affected, how to check without making things worse, and what to rotate.
What happened to LiteLLM 1.107.0
According to LiteLLM's incident report, the project's release pipeline was compromised on the morning of October 21 and pushed version 1.107.0 to PyPI and to its Docker registry. The release contained compiled malware that steals credentials and loads remote code execution tools. LiteLLM pulled the release, and it says customers on its private enterprise release were not affected.
The exposure windows from the report, all on October 21, 2026:
| Where | What was malicious | Window (UTC) |
|---|---|---|
| PyPI | litellm 1.107.0 wheels |
11:39 to 13:23 |
| Docker | v1.107.0, latest, main-latest and main-stable tags |
11:46 to 14:20 |
LiteLLM says the official v1.107.0 source tag on GitHub does not contain the malicious files, so the problem is in the published packages, not the project's source code. As of its last update at 20:30 UTC on October 21, LiteLLM described the incident as contained, with the investigation still in progress.
Am I affected?
The report says you are affected if either of these is true:
- You installed an unpinned
litellmwith pip between 11:39 and 13:23 UTC on October 21. That includes a fresh install, an upgrade, a CI build, or another package that depends onlitellmwithout pinning it. - You pulled or ran the Docker image tags
v1.107.0,latest,main-latestormain-stablebetween 11:46 and 14:20 UTC on October 21.
If you pin an exact earlier version, such as litellm==1.106.2 in a lockfile, and none of your images were rebuilt in that window, you were not exposed to this release.
How to check without making it worse
The malicious package ships startup files that Python runs automatically, so starting any Python program in an infected environment runs the payload again, including pip itself. Security researchers at StepSecurity and Datadog Security Labs identified the files as cook.pth, cook.py and sitecustomize.py in site-packages. LiteLLM's report suggests checking with pip show litellm, but on a machine you suspect, search the filesystem first so you do not start Python:
# Look for the release and the implant files without starting Python
find / \( -name 'litellm-1.107.0.dist-info' -o -name 'cook.pth' -o -name 'cook.py' \) 2>/dev/null
find / -path '*site-packages/sitecustomize.py' 2>/dev/null
# The backdoor's lock file and the stealer's marker files live in /tmp
ls -la /tmp/remote_code_loader.lock /tmp/.pc_once_* 2>/dev/null
Run the searches in every virtual environment, container image and CI cache that could have installed packages on October 21. A sitecustomize.py can be legitimate, because some Python setups ship one, so look at where it sits and when it appeared before drawing conclusions.
LiteLLM's report is clear about what the result means: finding any of these files confirms exposure, but not finding them does not prove the environment is clean. If the timing fits, act as if you were hit.
For Docker, check when you last pulled or rebuilt anything based on the latest, main-latest or main-stable tags, and whether a deployment restarted onto a new image during the window.
What to do if you installed 1.107.0
LiteLLM's report lists these steps, in this order:
- Do not start with
pip install. Reinstalling runs Python, which runs the payload again. - Remove the implant. Delete
cook.pth,cook.py,sitecustomize.pyand their matching__pycache__.pycfiles from every affectedsite-packagesdirectory. - Stop the backdoor. Kill the detached Python process that holds
/tmp/remote_code_loader.lock. - Reinstall a safe version. Pin
litellm==1.106.2. LiteLLM says rebuilding the virtual environment or image from scratch is better than cleaning it in place. - Assume the data left. If 1.107.0 ran on a host with outbound internet access, assume the stolen credentials were sent, even if no marker file shows it.
- Rotate everything the host could reach (see the next section).
- Look for use of the stolen credentials. On AWS, check CloudTrail for
GetCallerIdentitycalls from the instance role around the install time, and for any use of those credentials from outside your infrastructure. Do the same in other clouds' audit logs.
For a production host, the safest path is to take it out of service, build a fresh one from a clean, pinned image, and only then bring it back.
Which secrets to rotate
The report lists what to rotate on any host that ran 1.107.0:
- The instance or task IAM role, or any other cloud identity the machine used.
- Every AI provider API key stored in the LiteLLM proxy's database.
- The proxy's master key and all virtual keys issued to users and apps.
- The database password in
DATABASE_URL. - Any secret in the environment of any process on that host, not just LiteLLM's.
Researchers at Chainguard also list SSH keys, CI/CD secrets and browser-stored passwords among what the stealer collects, so include those if the machine was a developer laptop or a build runner. When you create replacement database passwords or shared secrets, make them long and random; the Password Generator does that in your browser, and the Password Entropy Calculator shows how strong a given format is. Revoke the old values at the provider, not just in your config, or the stolen copies keep working.
Why this attack spread so quickly
Two details made 1.107.0 dangerous.
It ran without an import. A .pth file in site-packages is read by Python at every startup, and so is sitecustomize.py. That means a machine was exposed as soon as the package was installed, even if no code ever imported LiteLLM, and every later Python command ran the payload again.
The source code looked clean. LiteLLM says attackers used developer credentials, apparently stolen GitHub CLI OAuth tokens, to run a staging build from a lookalike repository, Berri-AI/litellm, and a second developer credential passed the production approval step. LiteLLM believes the tokens were taken from the logs of an internal LiteLLM deployment exposed to the internet. Because the GitHub tag did not contain the malware, reviewing the source would not have caught it; only the published package was bad.
This is LiteLLM's second supply-chain incident this year. In March, its security update described malicious 1.82.7 and 1.82.8 releases that were on PyPI for about 40 minutes on March 24, 2026, also carrying a credential stealer, which LiteLLM believes came in through Trivy, a tool in its CI security scanning workflow. The project rebuilt its release pipeline after that, starting with v1.83.0.
How to protect yourself from the next bad release
The same habits limit the damage from any compromised package, not just this one:
- Pin exact versions and hashes. A lockfile with hashes, such as
pip-compile --generate-hasheswithpip install --require-hashes -r requirements.txt, refuses any file that does not match what you reviewed. The File Hash tool computes a downloaded wheel's SHA-256 in your browser so you can compare it with the hash PyPI lists. - Do not deploy floating tags. Tags like
latestandmain-stablechanged under people in this incident. Deploy images by digest, and update the digest on purpose. - Wait a little before upgrading. Both malicious LiteLLM releases this year were pulled within about two hours. A short delay before taking new versions into production, plus a review of what changed, keeps you out of that window. The Text Diff tool helps compare two
pip freezeoutputs or lockfiles to see exactly what moved. - Keep secrets out of reach. Give each service only the keys it needs, use short-lived cloud credentials, and keep provider keys out of the environment of unrelated processes, so one infected host exposes as little as possible.
The PHP project also shipped an urgent fix this week; see the PHP critical security update if you run PHP servers. For another recent case where a trusted supplier's keys were the weak point, see the eMudhra certificate authority compromise.
Common questions
Which LiteLLM version is safe? LiteLLM says every version before 1.107.0 is safe from this incident and recommends pinning litellm==1.106.2. Avoid 1.82.7 and 1.82.8, the versions from the March incident.
I only use LiteLLM as a library, not the proxy. Am I affected? Yes, if you installed 1.107.0 in the window. The payload runs at Python startup, so it did not matter how your code used LiteLLM or whether it imported it at all.
Is uninstalling LiteLLM enough? No. Uninstalling does not undo stolen credentials, and running pip in an infected environment runs the payload again. Remove the implant files, rebuild the environment, and rotate secrets.
Was the Docker image affected too? Yes. The v1.107.0, latest, main-latest and main-stable tags served the malicious image between 11:46 and 14:20 UTC on October 21, 2026. LiteLLM removed the v1.107.0 image and pointed the other tags back to safe builds.
Is there a CVE for this? As of October 22, 2026, LiteLLM's incident report is the official advisory, and we found no CVE assigned to this release. Check the report for updates as the investigation continues.