Skip to content

Back to the catalog

litellm 1.107.0 Compromised on PyPI: Backdoored Wheels Drop a Credential Stealer and an Hourly Remote Code Loader
stepsecurity.iowriteup

litellm 1.107.0 Compromised on PyPI: Backdoored Wheels Drop a Credential Stealer and an Hourly Remote Code Loader

litellm 1.107.0 was published to PyPI on 21 October 2026 with all seven wheels backdoored through an injected `data = "cook"` maturin build line. The wheels drop cook.pth, cook.py and sitecustomize.py, which run on every Python start. They install a "privcollect" credential stealer (browser, SSH, cloud, AI coding tool and LiteLLM proxy database secrets, sent to litellm.dev) and an hourly GitHub dead-drop remote code loader. The post gives IOCs, detection commands and recovery steps.

TL;DR StepSecurity dissects the backdoored litellm 1.107.0 PyPI wheels, covering the .pth-triggered stealer, the hourly remote loader, IOCs and cleanup.
Document

What it is

litellm 1.107.0 was published to PyPI on 21 October 2026 with malware in all seven compiled wheels (macOS, Linux glibc and musl, Windows). The release has since been removed from PyPI. The StepSecurity post says this is the second LiteLLM compromise of 2026, after 1.82.7 and 1.82.8 in March. The sdist carries no payload, but its pyproject.toml has a data = "cook" line under [tool.maturin] that is absent at git tag v1.107.0 (commit 66c8f5b1a9). The wheels carry no PyPI provenance attestations, so nothing ties the upload to a CI run.

How it works

The wheels set Root-Is-Purelib: false, so pip copies cook.pth, cook.py and sitecustomize.py into the top level of site-packages. Python runs them on every interpreter start, with no import litellm needed. cook.pth is import cook. Debian and Ubuntu system Python may ship an earlier sitecustomize.py that shadows the injected one, but the .pth path is unaffected.

Two payloads run:

  • privcollect stealer (cook.py, one layer of zlib and base64). It runs 16 modules on a daemon thread: browser passwords, SSH/GPG/TLS keys, cloud and registry credentials, .env files, cloud metadata credentials, CI secrets, /proc/<pid>/environ of every readable process, configs of 20+ AI coding tools, and shell history. If DATABASE_URL is set, it dumps LiteLLM_CredentialsTable and LiteLLM_ProxyModelTable (upstream provider keys) through the proxy's Prisma client. Data is encrypted with AES-256-CBC, the key is wrapped with RSA-4096, and it is sent by plain HTTP POST to http://www.litellm.dev/healthcheck. The marker /tmp/.pc_once_72129118c59f5636c0bb is written only after an HTTP 200, so a failing exfiltration means the stealer reruns on every Python start.
  • Hourly remote code loader (sitecustomize.py). It takes a lock at /tmp/remote_code_loader.lock, forks a detached daemon, and every hour reads a hostname from domain.txt in the GitHub repo letters9813/pythonclient-test. It then downloads http://<host>/codepy and runs it with exec(). It also embeds a second copy of the stealer.

The attacker prepared in advance: litellm.dev was registered on 13 October 2026 at 00:45 UTC, and the GitHub account was created six hours later.

Preconditions / Affected

  • Any install of 1.107.0 from a wheel. Nearly all installs use wheels, and open-ended litellm>= constraints or lockfile refreshes would have resolved to it.
  • LiteLLM released 12 times across four minor lines between 17 and 21 October 2026, so unpinned CI is likely exposed.
  • Proxy hosts with DATABASE_URL set lose stored provider keys, plus the master and salt keys from the environment.
  • On Windows the loader fails silently (no fcntl or os.fork), but the stealer runs, and likely reruns on every start because the marker path does not resolve.

What to do

Detect on hosts:

find / -name cook.pth -path "*site-packages*" 2>/dev/null
ls -la /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock 2>/dev/null
lsof /tmp/remote_code_loader.lock 2>/dev/null

Detect in repos:

grep -rniE "litellm[=<>~! ]*1\.107\.0([^0-9rc]|$)" . --include=requirements*.txt --include=*.lock --include=pyproject.toml --include=Pipfile*

Recover, in this order:

  1. Kill the process holding /tmp/remote_code_loader.lock (parent PID 1, working directory /). Uninstalling the package alone does not stop it.
  2. Delete cook.pth, cook.py and sitecustomize.py from every site-packages (pip uninstall litellm removes them, but verify), delete the marker file, and reinstall with pip install 'litellm==1.106.2'.
  3. Rotate everything the host could reach: cloud keys and role sessions, SSH/GPG keys, browser passwords and cookies, registry and Git tokens, Kubernetes and Vault tokens, CI secrets, AI tool tokens. On proxies, also rotate all stored provider keys, the master key and the salt key.
  4. Block litellm.dev at DNS or egress and alert on raw.githubusercontent.com/letters9813/.
  5. Search network logs for litellm.dev, the dead-drop URL, and any path ending /codepy.

Other IOCs: header X-Token: XWiA8gZNa7NcX2XRoAEb, the MSIE 7.0 User-Agent, temp dirs .pc_sq_* and .pc_e_*, and PRIVCOLLECT_ACTIVE=1. In CI, any runner call to litellm.dev means the stealer ran, so treat every secret exposed to that job as stolen.

Caveats

  • At the time of analysis domain.txt was empty, so the /codepy stage was not armed. Earlier values were localhost:18909 and test.test.com:18909. One commit to that file would give code execution on every infected host within an hour.
  • A request to /codepy means attacker code ran, and the scope is then larger than the post analyses.
  • The post does not say how the wheels were altered: a compromised build environment or stolen PyPI credentials.
  • The post's file hash table and timeline were not in the fetched text.

Organisations named here

  • credential stealer
  • dead drop
  • letters9813
  • litellm.dev
  • remote code loader
  • sitecustomize.py
  • T1195.002

Technologies named here

  • Dev Machine Guard
  • LiteLLM proxy and gateway hosts with DATABASE_URL set
  • StepSecurity Threat Center
  • maturin
  • lsof / fuser / find / grep
  • Debian and Ubuntu system Python
  • Windows
  • Clean version recommended
  • LiteLLM
  • PyPI
  • Python
  • pip
  • GitHub
  • Harden-Runner

Techniques named here

  • Python startup hooks
  • Obfuscated loader
  • Encrypted exfiltration
  • Lookalike domain litellm.dev behind Cloudflare
  • Execution guards

Threat actors named here

  • privcollect
  • cook.pth