
ByAhsan Nadeem@ashtech52Lead Full-Stack Engineer
On 21 October 2026, a poisoned release of LiteLLM, the open-source gateway many teams put between their apps and OpenAI, Anthropic or Google, sat on PyPI and Docker Hub for about two hours, long enough for roughly 49,000 downloads. It stole whatever keys the machine could reach, and it ran even if your code never imported LiteLLM.
This LiteLLM supply chain attack is the project's second of 2026. Below: a quick self-check, the timeline, what to rotate and the build habits that stop the next one. Most of those habits live in your pipeline, which our CI/CD pipelines work sets up.
Am I affected by the LiteLLM attack? The 30-second answer
You're at risk if any environment installed litellm 1.107.0, or ran a LiteLLM Docker image on a floating tag, on 21 October 2026 during the roughly two-hour window. The malware ran whenever Python started, so if that machine had internet access, assume the keys it could reach were stolen. Pinning 1.106.2 or earlier kept you out of this incident.
You're probably affected if:
- An environment installed
litellm==1.107.0from PyPI on 21 October 2026, roughly between 11:39 and 13:23 UTC. - A container ran
ghcr.io/berriai/litellmor the Docker Hub image with the tagv1.107.0,latest,main-latestormain-stable, pulled between 11:46 and 14:20 UTC that day. - A dependency pulled in LiteLLM unpinned and got 1.107.0.
LiteLLM says its private enterprise registry was not touched.
The LiteLLM supply chain attack, minute by minute
This timeline follows LiteLLM's canonical record of 23 October, which corrected early assumptions it called "inaccurate or incomplete" (times UTC).
When | What happened |
|---|---|
27 May 2026 | A master key for LiteLLM's experimental Agent Platform is committed to a public repository in an |
10 October, 21:27 | Using that key, the attacker gets the Agent Platform API to return a GitHub organisation owner's GitHub CLI token. |
10 October, 22:11 | With the owner's token, the attacker runs workflows that post CI secrets, including GitHub tokens, to |
21 October, 10:08 | The owner's token overrides branch protection on the private release workflow. |
21 October, 10:46 | A build runs from a lookalike repository, |
21 October, 11:11 | A maintainer's stolen token approves the production release gate. |
21 October, 11:39:51 | Seven malicious |
21 October, 11:46:56 | Poisoned images are published to Docker Hub and GHCR. |
21 October, 11:53 | Another stolen credential deletes the workflow records. |
21 October, 12:06 | A community member opens GitHub issue #47826 reporting the compromise. |
21 October, by 13:23 | PyPI quarantines 1.107.0. |
21 October, 14:20 | The last Docker Hub tags are removed or repointed. |
Sources differ on the clean-up times. Datadog and Wiz put PyPI's quarantine at about 13:20 and image removal at about 13:53; LiteLLM says GHCR was clean by 13:51 but Docker Hub tags pointed at the bad image until 14:20. If you pull from Docker Hub, use the later time.
The stolen data was used fast. Wiz saw AWS instance-role credentials taken from victims being tested from two IP addresses between 16:20 and 17:01 UTC.
Early coverage blamed stolen GitHub CLI tokens from three engineers: broadly right, but the 23 October record adds the first link (an unrevoked key leaked nearly five months earlier) and rules out an early theory that the tokens came from an internal deployment's logs.
Why Python .pth startup hooks make this nastier than a normal malicious package
Most malicious packages need importing; this one didn't. The wheel dropped three files into site-packages, outside the litellm folder:
- `cook.pth`, containing one line,
import cook. - `cook.py`, the credential stealer.
- `sitecustomize.py`, a backdoor loader.
Python reads every .pth file in site-packages each time it starts, executes any line beginning with import, and imports any module called sitecustomize. Python's documentation says these lines "are always run at Python startup ... regardless of whether a particular module is actually going to be used." They're now marked deprecated, but they still run.
In practice:
- Any Python process ran the stealer: tests, a Jupyter kernel, a cron job. Microsoft saw a Windows case where installing an unrelated dependency triggered it.
- `pip uninstall litellm` doesn't remove it. The files sit outside the package folder.
- Checking with Python can re-trigger it. Running
pythonorpipin a suspect environment starts the hooks again. - The source code looked clean. The official v1.107.0 tag never contained the payload. Endor Labs found one added line in the build settings,
data = "cook"inpyproject.toml, copied acook/folder that isn't in the public source into the wheel.
The line worth remembering: with a `.pth` hook, installing the package is the same as running it, every time Python starts.
What the malware stole
Microsoft, Datadog and Wiz agree on what cook.py collected:
- Cloud: AWS, Google Cloud and Azure credentials, including instance-role credentials from metadata services; Kubernetes, Docker, Vault and Terraform secrets.
- Developer secrets: SSH, GPG and TLS keys; Git, npm and PyPI tokens;
.envfiles; shell history; process environment variables. - AI tools: provider API keys and sessions for AI coding assistants, IDEs and MCP configs.
- Browsers: saved passwords and cookies.
- LiteLLM's own database: up to 500 rows per query from
LiteLLM_CredentialsTableandLiteLLM_ProxyModelTable, where the upstream provider keys live.
The haul was encrypted and posted to www.litellm.dev/healthcheck, an attacker-controlled lookalike domain.
Separately, sitecustomize.py started a background process on Unix-like systems that checked a GitHub file hourly for a server address, then would download and run code from it. That file only ever held test values, so no second stage was seen.
Why AI gateways are prime targets
An AI gateway exists to hold every provider key so your apps don't have to. One compromised LiteLLM proxy can hand over your OpenAI, Anthropic, Google and Bedrock keys at once, plus its database password and cloud role.
In August 2026, Microsoft told defenders to "treat AI gateways as Tier-0 secrets stores", the most sensitive tier, and this payload carried code written specifically to read LiteLLM's credential tables. Prompt injection attacks what an AI system says; this attacked the keys behind it (our prompt injection attack examples cover the other side).
How to check if LiteLLM 1.107.0 is on your systems, step by step
Microsoft advises inspecting a suspect environment from a clean machine, not by running Python inside it. Even LiteLLM's suggested pip show litellm restarts the hooks, so use it only where you're rebuilding anyway.
- Search lock files. Look for
litellm1.107.0inuv.lock,poetry.lock,Pipfile.lockandrequirements*.txtin every repository. - Look for the files. Search every
site-packagesforcook.pth,cook.py,sitecustomize.py,__pycache__/cook*.pycand alitellm-1.107.0.dist-infofolder. On Linux or macOS,find / -name cook.pth 2>/dev/nullis a start. - Check temp files and processes. A Python daemon holding
/tmp/remote_code_loader.lockmeans the backdoor is running. The marker/tmp/.pc_once_72129118c59f5636c0bbmeans data was sent; its absence proves nothing. - Check images by digest. Run
docker image ls --digestsand look forsha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e. LiteLLM's post lists separate digests for thelitellm-databaseandlitellm-non_rootimages. - Search CI logs and caches. Any job between 11:39 and 14:20 UTC on 21 October that installed LiteLLM unpinned or pulled a floating tag is suspect. Check pip and uv caches and internal mirrors too, because a cached copy can be installed later.
- Check network logs for connections to
www.litellm.devor the headerX-Token: XWiA8gZNa7NcX2XRoAEb.
For the March incident, look for versions 1.82.7 and 1.82.8 and a file called litellm_init.pth.
What to do if you find it: the response checklist
LiteLLM's rule: if 1.107.0 ran on a host with outbound internet access, assume the theft succeeded.
- Isolate affected laptops, build agents, containers and gateway hosts, and stop automation restarting Python on them.
- Kill and delete. Stop the daemon holding the lock file and delete
cook.pth,cook.py,sitecustomize.pyand their.pycfiles. Don't runpip installfirst: it re-runs the hooks. - Rebuild, don't repair. Rebuild from scratch, pinned to
litellm==1.106.2or one of the signed releases LiteLLM has shipped since 24 October (such as 1.106.4). - Rotate from a clean machine everything the malware could reach (see "What the malware stole" above, and the list below).
- Hunt for misuse. In AWS CloudTrail, look for
GetCallerIdentityand Bedrock listing calls from your roles around install time, and any use of those credentials from outside your network. Check provider dashboards for unexpected spend.
Pay special attention to:
- Cloud: the instance or task IAM role, not just access keys.
- LLM keys: every provider key in the proxy database, plus the master key and all virtual keys.
- Database and GitHub: the
DATABASE_URLpassword andghCLI logins. - Sessions: revoke browser and AI tool sessions too; Microsoft notes that rotating a key doesn't always end live sessions.
It's a long list, but it's finite, and every step closes a specific door.
How to stop the next one
After March, LiteLLM had moved to trusted publishing, immutable Docker tags and signed images. The attacker didn't break those controls; they drove the real pipeline with real credentials, and the build provenance honestly recorded Berri-AI/litellm as the source. The answer is layers, not one control.
Control | What it does | Would it have helped here? |
|---|---|---|
Lock files with hashes | Installs exactly the files you tested ( | Yes, if you were pinned to 1.106.2 |
Delayed adoption | Ignores releases younger than a set age: uv's | Yes: both poisoned LiteLLM releases were pulled within hours |
Image digests, not tags | Runs | Yes: floating tags were repointed at the bad image |
Check provenance, not just signatures | Confirms the source repository named in the attestation is the real one | Yes: the provenance named the lookalike fork |
Scoped, short-lived tokens | Uses fine-grained tokens with expiry and OIDC instead of personal CLI logins | Partly: the chain started with a personal owner token and an unrevoked key |
Egress allowlists | Lets gateway and build hosts reach only the APIs they need | Yes: posts to |
Two-person release approval | Requires a second human for each release | Partly: that week LiteLLM had relaxed this rule and temporarily widened release permissions |
Three habits matter most:
- Delayed adoption is the cheapest win. Both LiteLLM compromises this year were caught the same day, so a seven-day wait would have skipped both. Keep a fast path for real security fixes.
- Revoke leaked keys; don't just delete the commit. An overwritten commit doesn't make a key useless; only revoking does.
- Fence off the gateway. Give each app its own virtual key with a spend limit, and run the gateway as a non-root container with no other credentials on the host, as in our Docker containerisation work. For CI, our guide to GitHub Actions and AWS OIDC replaces stored keys with short-lived ones.
The npm ecosystem learned the same lessons in 2025; our npm supply chain attacks article covers the JavaScript side.
The March 2026 incident: same project, different route
On 24 March 2026, versions 1.82.7 and 1.82.8 appeared on PyPI from 10:39 UTC and were live for about 40 minutes before quarantine, LiteLLM says. It treats anyone who installed between 10:39 and 16:00 UTC as possibly affected.
That attacker skipped the release pipeline: LiteLLM believes the compromise came through Trivy, a security scanner in its CI, and the packages were uploaded straight to PyPI. Version 1.82.8 used the same trick, a litellm_init.pth startup hook.
Datadog links March to a campaign called TeamPCP and says no connection to October has been established.
Frequently asked questions
Is LiteLLM safe to use now?
As of 26 October 2026, the malicious 1.107.0 has been removed, 1.106.2 is the last version published before the incident, and LiteLLM resumed releases on 24 October (1.106.4 is the latest) with a new image-signing key. LiteLLM says it is revoking every internal token and has removed GitHub permissions from its release workflow. The problem was the release process, not the code, so pin exact versions by hash and wait a few days before upgrading, whichever gateway you use.
What is a .pth file in Python, and why is it dangerous?
A .pth file in site-packages normally just adds folders to Python's import path, but any line in it starting with import runs every time Python starts, whether or not your code uses that package. That turns one tiny file into code that runs in every Python process, and it survives pip uninstall.
Was the LiteLLM Docker image affected?
In October, yes. The images on Docker Hub and GHCR tagged v1.107.0, latest, main-latest and main-stable pointed at a poisoned image from 11:46 UTC until between about 13:51 and 14:20 UTC on 21 October 2026, so anyone running a floating tag could have pulled it without choosing 1.107.0. In the March 2026 incident, the official Docker image was not affected because it pinned its dependencies.
The bottom line
The way into the LiteLLM supply chain attack wasn't clever: a leaked key nobody revoked, a few personal tokens, and a build tool told to copy one extra folder. The defences are just as ordinary: pin by hash, wait before upgrading, run images by digest, scope your tokens and limit where your gateway can talk to. Treat the box that holds every AI key like the box that holds every password, because it is one.
Start today with step 1 of the check above: search your lock files for 1.107.0. Running an AI gateway or a Python build pipeline and not sure how exposed it is? Book a free consultation and we'll go through your dependency pinning, secrets and egress rules with you.
Sources
- LiteLLM, Contained: Oct 21, 2026 LiteLLM release v1.107.0 Compromised (21 October 2026, updated 23 October 2026): https://docs.litellm.ai/blog/security-incident-oct-21-2026
- LiteLLM, The attack chain behind the v1.107.0 LiteLLM release (23 October 2026): https://docs.litellm.ai/blog/security-incident-oct-21-2026-attack-chain
- LiteLLM, Security Update: Suspected Supply Chain Incident (24 March 2026, updated 27 March 2026): https://docs.litellm.ai/blog/security-update-march-2026
- LiteLLM, Announcing CI/CD v2 for LiteLLM (30 March 2026): https://docs.litellm.ai/blog/ci-cd-v2-improvements
- GitHub, BerriAI/litellm release v1.106.4 (25 October 2026): https://github.com/BerriAI/litellm/releases/tag/v1.106.4
- GitHub, BerriAI/litellm issue #47826, litellm 1.107.0 compromised (21 October 2026): https://github.com/BerriAI/litellm/issues/47826
- Microsoft Security Blog, Inside the LiteLLM 1.107.0 supply chain compromise: Credential theft through Python startup hooks (23 October 2026): https://www.microsoft.com/en-us/security/blog/2026/10/23/inside-the-litellm-1-107-0-supply-chain-compromise-credential-theft-through-python-startup-hooks/
- Microsoft Security Blog, When AI infrastructure becomes the target: Securing gateways and control points (26 August 2026): https://www.microsoft.com/en-us/security/blog/2026/08/26/when-ai-infrastructure-becomes-target-securing-gateways-control-points/
- Datadog Security Labs, LiteLLM supply chain compromise: What you need to know (21 October 2026): https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-docker
- Wiz, LiteLLM Compromised, Steals Credentials (21 October 2026, updated 22 October 2026): https://www.wiz.io/blog/litellm-compromised-steals-credentials
- Endor Labs, LiteLLM 1.107.0 Compromised: Python Startup Hooks Steal Cloud, AI, and Proxy Credentials (21 October 2026): https://www.endorlabs.com/learn/litellm-1-107-0-compromised-python-startup-hooks-steal-cloud-ai-and-proxy-credentials
- Python documentation, site: Site-specific configuration hook: https://docs.python.org/3/library/site.html
- pip documentation, pip install (
--uploaded-prior-to,--require-hashes): https://pip.pypa.io/en/stable/cli/pip_install/ - uv documentation, Settings reference (
exclude-newer): https://docs.astral.sh/uv/reference/settings/#exclude-newer

