
LiteLLM 1.107.0 PyPI Wheel Contains a Credential Stealer and Persistent Python Backdoor
LiteLLM 1.107.0 macOS x86-64 PyPI wheel analyzed by OpenSourceMalware contains three injected files (cook.pth, cook.py, sitecustomize.py) that run on every Python start. The payload, called privcollect, steals browser, SSH, cloud, CI/CD and AI-tool credentials, then uploads an AES/RSA-encrypted bundle to www.litellm.dev/healthcheck. A forked loader also fetches domain.txt from GitHub and executes /codepy hourly. The post lists IOCs, hashes and remediation steps.
What it is
LiteLLM 1.107.0 on PyPI shipped a malicious wheel. OpenSourceMalware analyzed the macOS x86-64 build (litellm-1.107.0-cp310-abi3-macosx_10_12_x86_64.whl, SHA-256 7598727f209d717041db37f7dca271d3a7d328a279890e0e1d55375729aeb86d). Upwind reported on 21 October 2026 that all seven 1.107.0 wheels carry the same three injected files and that the payload is absent from the v1.107.0 git tag. How the publishing credential or build environment was compromised is unknown. This is the second LiteLLM PyPI compromise in 2026, after versions 1.82.7 and 1.82.8 in March. The post does not attribute either to a named actor.
How it works
cook.pthcontainsimport cook, so any Python start in the environment runs it. LiteLLM does not need to be imported.sitecustomize.pyis a second, independent startup path.cook.pyBase64-decodes, zlib-decompresses andexecs a 1,237-line collector called privcollect. Thesitecustomize.pyvariant carries the same collector.- The injected files are listed with valid hashes in the wheel's RECORD, and all 3,946 entries verified. Integrity checks against RECORD would therefore pass.
- The collector takes browser credentials, SSH, GPG and TLS keys, cloud and Kubernetes credentials, package-registry tokens, CI/CD secrets, AI-tool configs (Claude, Codex, Cursor and others), all environment variables, and
/proc/*/environon Linux. WhenDATABASE_URLis set, it also reads the LiteLLM credentials and model tables, which hold upstream provider keys. - It encrypts the data with AES-256-CBC, wraps the key with RSA-OAEP, and POSTs the bundle over plain HTTP to
http://www.litellm.dev/healthcheck. - The loader in
sitecustomize.pyforks, detaches, fetchesdomain.txtfromgithub.com/letters9813/pythonclient-test, downloadshttp://{domain}/codepy, executes it, and repeats every 3,600 seconds.
flowchart TD
A[Python starts] --> B[cook.pth: import cook]
A --> C[sitecustomize.py]
B --> D[Collect and POST to www.litellm.dev]
C --> E[Fork, fetch domain.txt]
E --> F{domain.txt empty?}
F -->|yes| G[Dormant]
F -->|no| H[Run /codepy hourly]Preconditions / Affected
- Any host, container, virtualenv, developer machine or CI runner where the 1.107.0 wheel was installed and Python then started.
- Upwind says
domain.txthas been empty since 20 October 2026 at 09:15 UTC, so the remote-code stage is dormant. OpenSourceMalware has not verified that history. The credential stealer does not depend on it. - The post scopes its claims to 1.107.0 only.
What to do
Detection:
- Search proxy, DNS and firewall logs for
www.litellm.dev, especiallyPOST /healthcheckwith headerX-Token: XWiA8gZNa7NcX2XRoAEb, anX-SHA256header, and the user agentMozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0). - Search for Python processes fetching the GitHub
domain.txtpath and then making plain-HTTP requests to/codepy. - Look for
/tmp/remote_code_loader.lockand/tmp/.pc_once_72129118c59f5636c0bb. The second marker confirms a successful upload. Its absence proves nothing, because container restarts and temp cleanup remove it. - File hashes:
cook.pth7f191632e7320705d154b85204f1ae546b543acbd7e8861229b76f5042b92bdb,cook.py9dd0a3926f96a37eb86cf1ee2310d9be93139cc4ebef3ef9e2efe9531390be25,sitecustomize.py34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa.
Remediation:
- Isolate affected systems and preserve the wheel, the
/tmpartifacts, process trees and network logs. - Remove
cook.pth,cook.py,sitecustomize.pyand matching__pycache__files from every affected site-packages using a shell, not Python. Any Python start, including pip, re-runs both payloads. - Kill the detached Python process holding
/tmp/remote_code_loader.lock. - Rotate every secret readable by the affected account from a clean system. Cover cloud and Kubernetes credentials, SSH, GPG and TLS keys, registry and publishing tokens, CI/CD and Git tokens, browser passwords and AI-provider keys.
- Review cloud, source-control, registry and identity audit logs for later use of those credentials.
- Rebuild affected environments from trusted artifacts. Removing the package cannot undo code already delivered through
/codepy.
Caveats
- The
/codepypayload was never retrieved, so second-stage behavior is unknown. - The post says
https://www.litellm.devappears to host an operator panel with victim data. This is unconfirmed and the analysis is ongoing. - No IP, host or owner is attributed to
litellm.dev. Upwind says the apex domain was registered on 13 October 2026. The legitimate project domain islitellm.ai. - The collection endpoint was not contacted.
Organisations named here
- letters9813/pythonclient-test
- sitecustomize.py
- www.litellm.dev
Technologies named here
- LiteLLM 1.107.0 on PyPI
- Upwind security research team
- OpenSourceMalware
- LiteLLM 1.82.7 and 1.82.8 on PyPI
- github.com/letters9813/pythonclient-test
- LiteLLM
- PyPI
- Python
- GitHub
- Upwind
Techniques named here
- Obfuscated payload
- Cloud metadata credential harvesting
- Persistent backdoor
- Execution guard markers
Threat actors named here
- Remote code loader in sitecustomize.py
- privcollect
- TeamPCP
- cook.pth
Related in Supply Chain


