LiteLLM's October 21 Compromise Puts Provider Keys at Risk

LiteLLM 1.107.0 and its latest Docker tags carried a credential stealer for about two hours on October 21, and the attack survives uninstalling. Rebuild on 1.106.2 and rotate every key the proxy held as a security incident.

By Rajesh Beri·October 24, 2026·10 min read
Share:
A server rack in a dim data centre with one 1U gateway server pulled halfway out on its rails, a red quarantine tag tied to its handle and a ring of physical keys lying on top of it.

Illustration generated using AI

If any host installed litellm 1.107.0 from PyPI, or pulled LiteLLM's latest, main-latest or main-stable container image between 11:39 and 14:20 UTC on October 21, 2026, treat it as compromised. Rebuild it on 1.106.2 and rotate every credential it could reach, starting with the upstream model provider keys stored in the proxy's database.

Uninstalling the package does not clean the host. The malware drops startup files that run on every Python launch, whether or not anything imports LiteLLM, and it was published through LiteLLM's own signed build process, so the artifacts looked legitimate. This is the second time this year that a LiteLLM build has carried a credential stealer.

LiteLLM is the open-source gateway many teams put in front of OpenAI, Anthropic, Bedrock and Vertex so that every app calls one endpoint. That design puts every provider key in one database. The October attacker's code went looking for exactly that database.

Who Is Exposed to the LiteLLM 1.107.0 Compromise?

You are exposed if a Python environment installed litellm==1.107.0, or a container ran one of the poisoned image digests, during a window of roughly two hours on October 21. LiteLLM's incident post gives the exact windows:

Channel What was poisoned Live (UTC, Oct 21)
PyPI all seven litellm==1.107.0 wheels 11:39:51 to about 13:23
Docker Hub v1.107.0, latest, main-latest, main-stable 11:46:56 to 14:20
GHCR the same four tags on litellm, litellm-database, litellm-non_root 11:46:56 to about 13:51

The poisoned Docker Hub index digest is sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e. LiteLLM says the v1.107.0 source tag on GitHub is clean, because the malicious build came from a lookalike repository, and that customers on the private enterprise build "were not impacted."

The exposures most teams will miss happened without anyone typing a command. A Kubernetes deployment that tracks main-stable and happened to restart or scale during those two and a half hours pulled the bad image on its own. A requirements file with litellm>= picked up 1.107.0 on any fresh build in the window, and StepSecurity notes that open-ended constraints like that are common in projects that depend on LiteLLM. It also points out that almost every install pulls a prebuilt wheel, and all seven wheels (macOS, Linux glibc and musl, Windows) carry the payload. Your internal PyPI mirror or caching proxy may still be serving the cached 1.107.0 wheel even though PyPI has frozen the release.

Datadog Security Labs puts the package at about 23 million weekly downloads. Nobody has published a count of 1.107.0 installs.

What Does the Malware Do Once It Lands?

It steals every secret it can find on the host, sends them out encrypted, and installs a loader that can fetch new code every hour. Three files land in site-packages: cook.pth, cook.py and sitecustomize.py.

The persistence trick is a documented Python feature. The standard library's site module executes any .pth line that starts with import, and it automatically imports a module named sitecustomize at interpreter startup. Both happen before your code runs. Running pip uninstall litellm therefore starts Python, re-runs the stealer, and leaves all three files in place.

Datadog's analysis lists what cook.py collects:

  • AWS, GCP and Azure credentials, including instance metadata, plus Kubernetes, Docker, Vault and Terraform secrets
  • SSH, GPG and TLS keys; Git, npm and PyPI tokens; .env files and shell history
  • LLM provider API keys and the sessions of AI coding tools, including Claude, Codex, Gemini, Cursor and Copilot
  • browser passwords and cookies
  • on a configured LiteLLM proxy, the database tables that store upstream provider credentials

StepSecurity found 16 collection modules, one of them, db_litellm, written to dump provider credentials and model configs whenever DATABASE_URL is set. The bundle is encrypted with AES-256 under an RSA-4096 key and posted to www.litellm[.]dev/healthcheck, a lookalike of the real domain. The stealer keeps retrying on every Python start until that server answers with HTTP 200.

The second stage is sitecustomize.py. It starts a detached daemon that, every hour, reads a domain from a file on GitHub, downloads code from that host and runs it. Datadog says the dead-drop file held only test values, so no second-stage payload was seen in the wild. LiteLLM's own advice is blunter: if 1.107.0 ran on an internet-connected host, "assume the exfil succeeded."

The indicators to search for, from Datadog and StepSecurity:

  • files cook.pth, cook.py, sitecustomize.py and their __pycache__ bytecode
  • /tmp/.pc_once_72129118c59f5636c0bb, the marker written after a successful run
  • /tmp/remote_code_loader.lock, held by the hourly daemon
  • environment variable PRIVCOLLECT_ACTIVE=1
  • outbound traffic to litellm.dev carrying the header X-Token: XWiA8gZNa7NcX2XRoAEb, or requests to raw.githubusercontent.com/letters9813/ and any path ending /codepy

LiteLLM warns that a missing file does not prove a host is clean. The public GitHub issue that first flagged the compromise is the place to watch for new indicators.


How Did Attackers Get Signed Builds Out of a Hardened Process?

They stole three engineers' GitHub credentials and ran LiteLLM's real release workflow against a fake repository, so the output was signed. Nothing about the artifacts looked forged, because the official machinery produced them.

That matters because LiteLLM had already hardened its process once. After the March compromise of versions 1.82.7 and 1.82.8, which BoostSecurity attributed to the TeamPCP campaign and where 1.82.8 used the same .pth startup trick, the company moved releases into a separate repository, used PyPI Trusted Publishing, made release tags immutable and started signing images. In March the attacker had pushed packages straight to PyPI with stolen credentials, outside the normal build. In October the attacker went through the normal build. Datadog notes that "no connection between the two compromises has been established."

The account of how the attacker got in has changed since the first report. LiteLLM's first post said a GitHub CLI token may have leaked into logs on an internal deployment. Its root-cause analysis published October 23, which it calls "the canonical source of truth," says the first token came from a different service. The chain, as LiteLLM now tells it:

  1. On May 27, 2026, a config file containing the master key for LiteLLM's internal Agent Platform, an experimental service for agents that file pull requests, was committed to a public repository. The commit was later force-pushed over, but the master key was never revoked.
  2. On October 10, the attacker used that key against the platform's API. One response returned the configuration of every managed agent, including a GitHub CLI OAuth token belonging to one of the two GitHub organization owners. LiteLLM says the token was "not associated with a service account and was not scoped down."
  3. Two more maintainer tokens were captured through CI workflows that posted repository secrets to webhook.site.
  4. On October 21, the owner token overrode branch protection and repointed the release workflow at Berri-AI/litellm, one hyphen away from the real BerriAI/litellm. The approval rule had been relaxed to "any two engineers" to speed up bugfix releases, and two stolen tokens met it. A third credential then deleted the workflow run records.

GitHub's own deployment environment controls include required reviewers, an option to prevent people approving runs they triggered, and restrictions on which branches and tags may deploy. Each of those assumes that an approving account belongs to the person behind it. An attacker holding two engineers' tokens satisfied a two-person rule, and an owner token could override the branch protection.

The case for staying on LiteLLM is real. The source tag was clean, a public GitHub issue flagged the build at 12:06 UTC, 26 minutes after the wheels went up, PyPI froze the release within two hours, the private enterprise registry was untouched, and the root-cause write-up is unusually candid. But two compromises in seven months, by different routes, tell you that the release process of any open-source gateway is part of your attack surface, and that a valid signature only proves which workflow built an artifact, not that the workflow pointed at the right source.

Which Keys Should You Rotate, and in What Order?

Rotate everything the host could reach, from a clean machine, starting with the credentials that cost money or reach production. The LiteLLM incident post and StepSecurity's write-up together name these:

  1. Every upstream provider key stored in the proxy database. These are the keys db_litellm was written to dump. Revoke them at each provider as well as in LiteLLM, then check provider usage logs for calls you did not make since October 21.
  2. The instance or task IAM role and any cloud keys on the host. LiteLLM recommends checking CloudTrail for GetCallerIdentity calls from the instance role around install time, and for that role's credentials being used from outside your infrastructure.
  3. The LiteLLM master key, the salt key and every virtual key you issued to teams. Reissuing virtual keys breaks every app that holds one, so schedule it with the app owners.
  4. The DATABASE_URL password.
  5. Anything else in the environment of any process on that host, plus SSH and GPG keys, registry tokens, and AI coding tool sessions on developer laptops that installed 1.107.0.

Do the cleanup in this order, per StepSecurity: kill the process holding /tmp/remote_code_loader.lock, delete the three files and their bytecode from the shell before running pip or python, then rebuild the image or virtualenv from scratch on litellm==1.106.2, with the container image pinned by digest. Do not clean in place.


What to Do About the LiteLLM Compromise

Today:

  1. Search every image registry, cluster and build log for the digest sha256:1bbcb1443bc9… and for litellm==1.107.0. Include developer laptops and notebook servers, which are the installs nobody inventories.
  2. Run a fleet search for cook.pth, sitecustomize.py in site-packages, the /tmp/.pc_once_ marker and the lockfile. Block litellm.dev at egress and alert on any /codepy request.
  3. On any hit, declare an incident and start the rotation list above. Do not wait for proof of exfiltration; LiteLLM says to assume it.

This Week:

  1. Purge 1.107.0 from your PyPI mirror and caching proxy, and pin litellm==1.106.2 with hashes in every lockfile.
  2. Change every LiteLLM deployment from a moving tag (latest, main-stable) to an image pinned by digest, and make upgrades a reviewed change.
  3. Ask your enterprise LiteLLM contact whether you can pull from the private registry, which the company says was not affected.

Before the Next Gateway Upgrade:

  1. Move provider keys out of the gateway's own database and into a secrets manager with per-key usage alerts, so a dump of one table is not a dump of your whole model bill.
  2. Audit your own release workflows for the same failures: an owner's long-lived personal token sitting in a service config, a two-approver rule any two stolen accounts can satisfy, and CI on arbitrary branches that can read secrets.
  3. Wait at least a few days before adopting any new gateway version, and read the release diff, in LiteLLM or whichever alternative you run.

The Bigger Picture

An AI gateway now holds the same class of secret as a payment processor's vault: keys that spend money on demand and reach every model your company uses. Attackers have noticed. This publication covered an eval sandbox that gave up a LiteLLM key in September, and the npm worm that reinfected developers through AI agent configs in August. October's chain started with a different kind of AI tool, an internal agent platform holding an owner's unscoped GitHub token, which is the kind of convenience setup many engineering teams have built this year.

Switching gateways does not remove the risk. A self-hosted Kong AI Gateway or any other proxy concentrates the same keys (our comparison of self-hosted LLM gateways covers the options). The defenses are the ones that worked for package registries a decade ago: pin by digest, mirror and scan before you promote, and treat a gateway's key store as tier-zero infrastructure.

Pull the digest list from your registry before you do anything else today.

Continue Reading

Share:

Frequently Asked Questions

Which LiteLLM versions and Docker tags were compromised in October 2026?

PyPI litellm==1.107.0 (all seven wheels) and the Docker Hub and GHCR tags v1.107.0, latest, main-latest and main-stable, which pointed to a poisoned image between 11:46:56 and 14:20 UTC on October 21, 2026 (about 13:51 on GHCR). LiteLLM says 1.106.2 is safe and the private enterprise build was not affected.

Does uninstalling litellm 1.107.0 remove the malware?

No. The package drops cook.pth, cook.py and sitecustomize.py into site-packages, which Python runs at every interpreter start. Running pip uninstall re-triggers the stealer. Kill the process holding /tmp/remote_code_loader.lock, delete the files from the shell, then rebuild the environment on 1.106.2.

Which keys should I rotate after the LiteLLM 1.107.0 compromise?

Every upstream provider key in the proxy database, the host's IAM role and cloud keys, the LiteLLM master and salt keys, every virtual key, the DATABASE_URL password, and any other secret in the host's process environments. Rotate from a clean machine and assume exfiltration succeeded.

How did attackers publish a signed malicious LiteLLM build?

Per LiteLLM's October 23 root-cause analysis, a master key for an internal agent platform leaked in a public repo in May and was never revoked. The attacker used it to obtain an org owner's GitHub token, stole two more, and ran the real release workflow against the lookalike repo Berri-AI/litellm.

Newsletter

More on AI Security, every Sunday

The week's enterprise AI news, AI Security included, in one Sunday email.

Weekly, free. Unsubscribe any time. Privacy

Latest Articles

View All →