What happened on 21 October
LiteLLM is an open-source Python library and proxy server that puts a single, OpenAI-style interface in front of many model providers. Teams use it as an SDK inside applications and as a self-hosted AI gateway that holds provider keys, issues virtual keys and tracks spend. Socket estimates about 23 million weekly downloads, which is why a malicious release travels fast.
LiteLLM says that at 4:00 AM PST on 21 October 2026 its release pipeline was compromised and pushed v1.107.0, which "contained compiled malware which steals credentials and loads remote-code execution tools". The package was removed from PyPI at 13:23 UTC and the last affected Docker Hub tag was repointed at 14:20 UTC. Help Net Security notes this is the project's second supply chain attack this year, after a compromise in March.
What is affected, exactly
| Channel | Affected artifact | Window (UTC, 21 October) |
|---|---|---|
| PyPI | litellm==1.107.0, all platform wheels | 11:39 to 13:23 |
| Docker Hub | Tags v1.107.0, latest, main-latest, main-stable | 11:46 to 14:20 |
| GitHub Container Registry | Same four tags on litellm, litellm-database and litellm-non_root | 11:46 until removed, by 13:51 |
| Private enterprise registry | Not affected | None |
| Earlier versions, including 1.106.2 | Not affected | None |
LiteLLM says the official 1.107.0 source tag does not contain the malicious files: the payload was added to the built wheels and images. That matters for one group only, people who build from source, and it means everyone else should judge exposure by what they installed or pulled, not by what is in the repository.
How the release was published
According to LiteLLM, the attacker held GitHub CLI credentials for three developer accounts. One was used to override branch protection and point the release workflow at a lookalike repository, Berri-AI/litellm instead of BerriAI/litellm. A second satisfied the production approval gate. A third deleted the workflow run records. LiteLLM traced the tokens to an unexpected user account on an internal LiteLLM deployment exposed to the internet, and believes the tokens were pulled from its logs. It says it has not confirmed how the attacker got into that deployment and suspects a recently patched vulnerability.
One detail is relevant to many readers' own environments. LiteLLM says it has seen Claude Code embed a user's GitHub CLI OAuth token in a response body, so a gateway that logs full response bodies can end up storing tokens. If you run any AI gateway with response logging switched on, it is worth checking what your logs contain and who can read them.
What the malware does, at the level defenders need
Three files are written into the root of Python's site-packages directory: cook.pth, cook.py and sitecustomize.py. Python processes .pth files and sitecustomize.py automatically at interpreter startup, so the stealer runs whenever any Python process starts in that environment. Your application does not need to import LiteLLM. Running pip, a test suite or an unrelated script is enough.
That is why LiteLLM warns against beginning remediation with pip install: pip is a Python program, and running it in an infected environment runs the stealer again.
What it collects
- Cloud credentials for AWS, Azure and Google Cloud, including AWS keys from
~/.aws/, environment variables and EC2 or ECS instance metadata, Google service account keys and Azure CLI tokens. - Kubernetes and Docker credentials.
- Git credentials, SSH and GPG private keys and shell history.
- AI provider API keys in environment variables or config files, and authentication files for AI coding tools including Codex, Claude, Gemini and Cursor.
- Saved browser logins, cookies and browsing history.
- Upstream provider keys and settings stored in the LiteLLM proxy's database. Researchers note this shows intent rather than proving success against any given deployment.
The data is encrypted and sent to a lookalike domain, litellm[.]dev. LiteLLM's guidance is blunt: if 1.107.0 ran on a host with outbound internet access, assume exfiltration succeeded. A second component on Linux and macOS checks a file on GitHub for a domain from which to fetch more code. Wiz says that file never held more than test values and the second stage was not seen active, and GitHub took the repository down, but the capability is why the affected host itself should be treated as compromised and not merely its secrets.
What the attacker did with the keys
Wiz reports that from 16:20 to 17:01 UTC on 21 October the attacker validated stolen AWS instance role credentials taken from CI runners and Kubernetes nodes, checked access to models on Amazon Bedrock, and in a small number of environments enumerated IAM roles, users and access keys. Wiz links the Bedrock checks to LLMjacking, the resale or misuse of someone else's paid model access. The gap between exfiltration and use was about four and a half hours, which is the clearest guide to the order in which to rotate.
Are you affected? The checks to run
You are affected if any environment ran pip install that resolved to 1.107.0, or started a container from one of the affected tags, during the windows above. The most common ways that happens without anyone choosing it are an unpinned litellm in a requirements file installed by CI, and a deployment that pulls litellm:latest or main-stable on restart.
Python environments
Do not run pip inside a suspect environment until the persistence files are gone. Check from outside it first, by listing the files on disk:
- Search every Python
site-packagesdirectory, including virtual environments, CI caches and notebook kernels, forlitellm-1.107.0.dist-info,cook.pth,cook.pyandsitecustomize.py. Asitecustomize.pycan be legitimate, so inspect any you find rather than assuming. - Look for the run-once marker file
/tmp/.pc_once_72129118c59f5636c0bb, the lock file/tmp/remote_code_loader.lock, and processes withPRIVCOLLECT_ACTIVE=1in their environment. - Once the files are removed,
pip show litellmin each environment confirms the installed version. LiteLLM says a result of 1.107.0 means treat the environment as compromised.
LiteLLM is explicit that finding these files confirms exposure, but not finding them does not prove an environment is clean. An ephemeral CI runner that installed 1.107.0 and was then destroyed will show nothing today and may still have sent its credentials.
Containers
- Check which digest your running and recently run containers used, with
docker images --digestsordocker inspecton the container, and in Kubernetes from each pod'simageIDin its status. The compromised Docker Hub image index issha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e. LiteLLM lists the GHCRlitellm-databaseindex as beginningsha256:c00f9d92c427andlitellm-non_rootassha256:7b00e91cd2fe. - Check pull history, not just what is running now. Any node, autoscaled instance or CI job that pulled
latest,main-latest,main-stableorv1.107.0between 11:46 and 14:20 UTC may have run the bad image even if it has since been replaced. Registry mirror logs and Kubernetes events help here. - Treat any container that ran the affected digest as compromised, and anything mounted into it or reachable from its service account as exposed.
Logs worth searching
- DNS and egress logs for
litellm[.]dev. - CloudTrail for
sts:GetCallerIdentityand Bedrock model listing calls from instance roles around and after install time, then for any use of those credentials from outside your own infrastructure. Wiz lists post-exploitation addresses168.100.8[.]57and165.227.201[.]8. - Your own GitHub audit log, if developer machines were affected, for workflow changes or approvals nobody remembers making.
Clean-up and rotation, in order
Upgrading alone is not enough. Moving to a safe version stops new infections, but the persistence files survive a package change and the credentials taken are already outside your control. Aikido's advice, reported by Help Net Security, is that anyone who installed 1.107.0 before it was pulled should treat their credentials as compromised and rotate them.
1. Contain the host
Kill the detached Python process holding /tmp/remote_code_loader.lock, then delete cook.pth, cook.py, sitecustomize.py and any matching cook*.pyc or sitecustomize*.pyc under __pycache__ from every affected site-packages. LiteLLM recommends rebuilding virtual environments and images from scratch rather than cleaning in place, and that is the better choice wherever it is practical. Reinstall pinned to litellm==1.106.2.
2. Rotate cloud credentials first
The attacker used AWS credentials within hours, so cloud access comes first: instance and task IAM roles (revoke active sessions, not just keys), long-lived access keys, Azure and Google Cloud credentials, and Kubernetes service account tokens and kubeconfigs. If you use AWS, check Bedrock usage and billing for model calls you did not make.
3. Source control and signing keys
Git tokens, GitHub CLI tokens, deploy keys, SSH keys and GPG keys. A stolen Git credential is how the next supply chain attack starts, and this incident itself began with stolen GitHub tokens.
4. The gateway's own secrets
For proxy deployments, LiteLLM lists every provider key stored in the proxy database, the master key and all virtual keys, and the DATABASE_URL password. Rotate provider keys at the provider, not just in LiteLLM.
5. Everything else on the host
Any secret in the environment of any process on the machine, AI coding tool tokens, and browser sessions for any account used on an affected workstation. A developer laptop that installed 1.107.0 should be treated as having lost its saved browser logins.
A secrets manager makes this order of work much faster, because rotation happens in one place and consumers pick up new values. If your keys currently live in .env files, this is the incident that justifies moving them; HashiCorp Vault, Infisical and Doppler are compared in Doppler vs HashiCorp Vault.
Pinning, hashes and what actually prevents the next one
Most teams hit by this did not decide to install 1.107.0. Their tooling decided for them, because a dependency or an image tag floated to the newest release. The fixes are unglamorous and they work.
Pin versions and check hashes
Install Python dependencies from a lock file that records an exact version and hash for every package, using pip-compile --generate-hashes with pip install --require-hashes, or the lock files produced by uv or Poetry. A hash lock would not have stopped someone deliberately upgrading to 1.107.0, but it stops a routine CI run quietly picking up a release that appeared two hours earlier.
Add a delay before new releases are eligible
This release was live for under two hours on PyPI. A rule that new versions are not installed until they are a few days old, which uv supports through its exclude-newer setting, would have skipped it entirely. The cost is that urgent security fixes need a deliberate override, which is the right default.
Pin images by digest, not tag
The tags latest, main-latest and main-stable were all repointed at the malicious image. A deployment that references litellm@sha256:... cannot be changed underneath you. Update the digest deliberately, through a pull request that someone reviews. Signing with Cosign proves which pipeline published an image, which is useful, but in this incident the pipeline itself was used, so signatures should complement digest pinning rather than replace it.
Scan dependencies for behaviour, not just CVEs
A new release that adds a .pth file and outbound network calls is the kind of change behavioural package scanners flag, and it was Socket, Aikido and Wiz that published the early analysis here. Socket and Aikido both work this way; see Aikido vs Socket. Hardened, minimal base images such as Chainguard reduce what a compromised container can reach; see Chainguard vs Snyk.
Limit what the gateway can reach
The damage here scaled with what the infected process could read. A gateway container with no cloud instance role, a narrowly scoped Kubernetes service account, egress restricted to model provider endpoints, and response-body logging off would have exposed far less. That is true whichever gateway you run.
Managed AI gateway alternatives, with honest trade-offs
Some teams will reasonably ask whether to keep running LiteLLM. The honest answer is that moving to a managed gateway changes who runs the supply chain rather than removing it. Every option below holds or brokers your provider keys, and every one has its own release pipeline. What changes is whether a bad release lands on your hosts, with your cloud credentials in reach, or on the vendor's. Our full list is on the LiteLLM alternatives page, with more in the APIs category.
| Option | Where it runs | What you gain | What you give up |
|---|---|---|---|
| LiteLLM, pinned and hardened | Your infrastructure | No migration; full control of keys and data | You own patching, pinning and isolation |
| Portkey | Hosted, or its open-source gateway self-hosted | Managed operation, routing and observability | Prompts and keys pass through a third party if hosted |
| OpenRouter | Hosted only | One key and one bill for many models | A marketplace in the request path; less control over provider accounts |
| Kong AI Gateway | Self-hosted or Kong's managed control plane | Fits teams already running Kong for APIs | Heavier to adopt if you do not |
| Cloudflare AI Gateway | Cloudflare's network | No servers to run; caching and logging at the edge | Tied to Cloudflare; fewer gateway features than a dedicated product |
Portkey
Portkey is the closest functional match to the LiteLLM proxy: routing, fallbacks, virtual keys and observability, available hosted or as an open-source gateway you run yourself. Self-hosting it puts you back in the same supply chain position as LiteLLM, so the security case for switching rests on the hosted version. See LiteLLM vs Portkey.
OpenRouter
OpenRouter is a hosted marketplace: you hold an OpenRouter key rather than keys for each provider, which shrinks the number of secrets you manage and so the number you would have had to rotate this week. In exchange your traffic and billing go through OpenRouter, and you rely on its controls for data handling. Check OpenRouter pricing against your current provider spend before moving volume.
Kong AI Gateway
Kong adds AI routing and policy to Kong Gateway. For organisations that already run Kong in front of their APIs it means one gateway and one policy model rather than two. For those that do not, it is a larger adoption than the problem warrants. See Kong Gateway vs LiteLLM and Kong Gateway vs Portkey.
Cloudflare AI Gateway
Cloudflare's AI Gateway runs on its network, so there is no package to install and no container to pull. It suits teams that mainly want logging, caching and rate limiting in front of providers and already use Cloudflare. It is lighter than a full gateway product, and depending on Cloudflare for the request path is its own concentration risk.
Observability-first
If what you mostly used LiteLLM for was spend tracking and logs, an observability tool may be a better fit than another gateway; Helicone vs LiteLLM covers that trade.
The case for staying
LiteLLM's response so far has been fast and unusually detailed, including the attack chain and the role of its own internal deployment. A team that pins by hash and digest, delays new releases, isolates the gateway and keeps secrets in a manager is in a better position on LiteLLM than a team that moves to a managed product and changes nothing else. Switching is worth doing for operational reasons. It is not, on its own, a security control.
Questions people ask
- Which LiteLLM versions are compromised?
Only 1.107.0. On PyPI that is
litellm==1.107.0, live from 11:39 to 13:23 UTC on 21 October 2026. On Docker the tagsv1.107.0,latest,main-latestandmain-stablepointed at compromised images between 11:46 and 14:20 UTC. LiteLLM says all earlier versions are safe, and 1.106.2 is the most recent safe release.- How do I check if I installed LiteLLM 1.107.0?
Look in every
site-packagesdirectory forlitellm-1.107.0.dist-info,cook.pth,cook.pyandsitecustomize.pybefore running any Python there, then usepip show litellm. For containers, compare image digests against the compromised indexsha256:1bbcb1443bc9...and check whether anything pulled the affected tags in the window. Not finding the files does not prove you are clean, especially on ephemeral CI runners.- Is upgrading or downgrading LiteLLM enough?
No. The malware writes files that run on every Python startup and survive a package change, and the credentials it collected have already been sent. Remove the persistence files, rebuild environments, reinstall pinned to 1.106.2, and rotate every credential the affected host could reach.
- Which credentials should I rotate first?
Cloud credentials, because Wiz saw the attacker validating stolen AWS instance role credentials about four and a half hours after exfiltration. Then Kubernetes tokens, Git and SSH keys, then the LiteLLM master key, virtual keys, stored provider keys and database password, then everything else in the host environment, including AI coding tool tokens and browser sessions.
- Was I affected if I only use the LiteLLM SDK and never imported it?
Installing it was enough. The malware runs through a
.pthfile andsitecustomize.py, which Python loads at startup, so any Python process in that environment triggered it whether or not LiteLLM was imported.- Were LiteLLM enterprise customers affected?
LiteLLM says enterprise customers running the private enterprise release from its private registry were not impacted. Enterprise users who installed from public PyPI or pulled public Docker tags should check as above.
- What are the alternatives to LiteLLM?
Portkey, OpenRouter, Kong AI Gateway and Cloudflare AI Gateway are the main managed or semi-managed options. A hosted gateway moves the supply chain risk to the vendor rather than removing it, so pinning, isolation and a secrets manager matter whichever you choose. See LiteLLM alternatives.
Sources
Every price, limit and date above was checked against these pages on the day shown. Where a figure has since moved, the vendor’s own page is the authority and this one is a snapshot.
- 1Contained: Oct 21, 2026 LiteLLM release v1.107.0 Compromised · LiteLLMLiteLLM's own account: affected artifacts and digests, timeline, persistence files, checks, remediation steps and the attack chain.Checked
- 2LiteLLM Compromised, Steals Credentials · WizCredential types collected, indicators of compromise, and the attacker validating AWS credentials and probing Bedrock afterwards.Checked
- 3LiteLLM hit by second supply chain attack this year, users urged to rotate credentials · Help Net SecurityAvailability windows, download scale from Socket, the earlier March incident and the advice that upgrading alone is not enough.Checked
