Security

LiteLLM's 1.107.0 release was live on PyPI for under two hours. It was built to steal your AI tool tokens.

A poisoned release of the popular LLM gateway went out through LiteLLM's own pipeline on October 21. The malicious code isn't in the source on GitHub, which is why reading the repo wouldn't have caught it.

·5 min read
Illustration for the LiteLLM 1.107.0 PyPI supply chain compromise

If you run LiteLLM, the first thing to do is run pip show litellm and look at the version number. If it says 1.107.0, or if a container pulled latest on October 21, read the rest of this with your credentials in mind.

LiteLLM is the open-source gateway a lot of teams use to talk to several AI providers through one interface. SOCRadar puts it at roughly 23 million downloads a week. On October 21 an attacker got a trojanized 1.107.0 published through the project’s official release process. It was on PyPI for about 100 minutes.

What happened, in order

All times are UTC. The attacker changed the release workflow at 10:08, and seven malicious wheels were uploaded to PyPI at 11:39. Poisoned Docker images followed at 11:46. PyPI pulled the release at 13:23, and Docker Hub tags were removed or repointed by 14:20. Those times come from LiteLLM’s incident report as relayed by the security firm SafeDep. LiteLLM’s own page wouldn’t render its text for me, so I’m leaning on SafeDep, JFrog and The Hacker News for the detail.

LiteLLM says the attacker held GitHub CLI credentials belonging to three developers, which it suspects were lifted from the logs of an internal deployment that was exposed to the internet. With an organization owner’s token the attacker got around branch protection. It then pointed the release workflow at a lookalike repository, Berri-AI/litellm, and used a second developer’s credential to clear the approval step. The official pipeline did the rest: it built, signed and published the poisoned files.

Why reading the code wouldn’t have helped

This is the part I keep thinking about. The source distribution has no malicious files. The tag on GitHub is clean. The only visible trace in the sdist is one added line in pyproject.toml, data = "cook", which tells the build tool to copy a folder called cook/ into the wheel. That folder exists nowhere in the public repo.

A reviewer who checks the repo or the sdist finds nothing. JFrog calls this the instructive part, since the payload rode in the platform-specific wheels. And because the pipeline itself signed the artifacts, a signature check would have passed too.

What the malware does

It installs three files into site-packages, cook.pth, cook.py and sitecustomize.py. Python runs them every time any interpreter starts, even a process that never imports litellm. That includes pip and CI jobs.

The stealer, which StepSecurity says calls itself privcollect, has 16 modules. According to SafeDep it goes after SSH keys, cloud credentials (AWS, Azure, Google Cloud, Kubernetes), CI/CD secrets, browser passwords, shell history and the provider API keys stored in a LiteLLM proxy database. It also reads the config and token files of AI coding tools, with Claude Code, Cursor, Codex and Gemini CLI on the list. Everything is encrypted and posted to a lookalike domain, www.litellm.dev.

The second payload is a background daemon on Linux and macOS. Once an hour it reads a server address from a file in a GitHub account, then downloads and runs whatever Python that server returns. That GitHub account was returning 404 by 13:40 UTC. SafeDep couldn’t recover the server address, so nobody outside the attacker knows what, if anything, was sent to infected hosts before then. JFrog notes that on Windows the daemon fails silently, but the stealer still runs.

How to check

SafeDep lists these markers: the three files in site-packages, a file at /tmp/.pc_once_72129118c59f5636c0bb (the stealer already uploaded), and /tmp/remote_code_loader.lock (the daemon has run). Clean versions are 1.106.2, 1.107.0rc1 and 1.107.0rc2.

SOCRadar says follow-on use of stolen AWS credentials has been observed as of October 22. If you were exposed, rotating everything the stealer touches is the only safe answer, not just upgrading. I’d start with cloud keys and CI secrets, then every LLM provider key that sat in a proxy database.

Source What it says about the cause
LiteLLM (via SafeDep) Stolen developer GitHub credentials, probably from exposed deployment logs
The Hacker News LiteLLM hasn’t yet found how the tokens were taken
JFrog Evidence doesn’t prove which system or credential was compromised

My take

This is the second time LiteLLM has been hijacked this year. JFrog ties the March versions 1.82.7 and 1.82.8 to an earlier campaign, and says the new one used different payloads and infrastructure. I don’t read that as a project that’s careless so much as one that sits in a spot attackers want. A gateway holds every provider key in one place, which makes it a better target than any single app.

Pinning matters here.

The uncomfortable lesson is for everyone who pulls latest. A two-hour window is short, but automated builds and fresh containers don’t care about windows. Pin versions, and think twice before letting a CI job install a release that is hours old. I’d also be wary of anyone telling you a signature check settles this one. It didn’t here.

For related reading on how attackers are using AI tooling, see the post on the AI agents that broke into more than 100 company sites.

Sources

  1. SafeDep: Compromised LiteLLM 1.107.0 on PyPI installs a credential stealer and backdoor
  2. JFrog Security Research: LiteLLM hijacked again
  3. The Hacker News: LiteLLM compromised in supply chain attack
  4. SOCRadar: New LiteLLM supply chain attack hits PyPI and Docker
  5. BerriAI/litellm issue #47826