> status: mostly fine. patch anyway.practical AI security · est. 2026

Brief · Both

LiteLLM 1.107.0 Was Trojanized: Check, Rotate, Rebuild

By alkizz ·

On Oct 21, someone ran LiteLLM's own release pipeline against a lookalike repo (Berri-AI/litellm, note the hyphen) and shipped a poisoned 1.107.0. Per LiteLLM's incident post, all seven PyPI wheels were live from 7:39 to 9:23 AM ET. The Docker Hub tags v1.107.0, latest, main-latest and main-stable pointed at the bad image from 7:46 to 10:20 AM ET, and the same tags on GHCR until no later than 9:51 AM ET. LiteLLM gives those times in UTC; I converted them. The bad artifacts are gone, and latest now points at 1.106.2. If you installed or started it in that window, removing it upstream doesn't help you.

What it did: the wheels drop cook.pth, cook.py and sitecustomize.py into site-packages, so the payload runs on every Python start, even if nothing imports litellm, and pip counts. cook.py is a credential stealer. It grabs cloud credentials (including instance-role creds from the metadata service), SSH and GPG keys, GitHub CLI and package-registry tokens, AI tool configs, browser passwords, the environment of every process it can read, and, if DATABASE_URL is set, every provider key in the proxy's LiteLLM_CredentialsTable. It encrypts all of it and POSTs it to www.litellm[.]dev, which isn't LiteLLM's domain. sitecustomize.py starts an hourly loader that fetches a domain from a GitHub dead drop and runs whatever Python that domain serves. The reporters and JFrog both found the dead drop empty, so no second stage has been seen. One commit could change that.

The stolen credentials are already in use. Wiz saw them tested about 4.5 hours after exfiltration, from 12:20 to 1:01 PM ET. AWS instance-role credentials from CI runners and Kubernetes nodes were checked with GetCallerIdentity, then bedrock:ListFoundationModels, which Wiz calls "consistent with LLMjacking." Wiz puts downloads of the bad version at about 49,000.

How it got in, according to LiteLLM: the attacker had GitHub CLI OAuth tokens for three LiteLLM engineers, one of them an org owner. The attacker used that token to disable branch protection and point the release workflow at the lookalike repo. As for where the tokens came from, LiteLLM says it has "observed specific situations in which Claude Code will embed a user's GitHub CLI OAuth token into a response body, and in situations where response bodies are logged, these tokens may appear in LiteLLM logs." It says its internal LiteLLM deployment was exposed to the internet and had an "unexpected, innocuously named user account," and it believes the attacker got in there and pulled the tokens from the logs. LiteLLM hasn't said what those situations are. It hasn't confirmed how the attacker reached the deployment either; it "suspect[s]" a recently patched vulnerability. It also says it's still confirming parts of this account. Treat it as LiteLLM's working theory, not a settled root cause.

My take: whichever tool put the token there, a gateway that logs full response bodies is a credential store nobody meant to build. Put it on the internet and it's somebody else's credential store.

What to do:

Tl;dr: if 1.107.0 never ran on your machines, fix your logging and go back to work. If it did, it's an incident: preserve, rotate, rebuild, in that order.

Sources

← All briefs