# LiteLLM Supply-Chain Compromise: Malicious v1.107.0 on PyPI and Container Registries Deploys 'privcollect' Credential Stealer and GitHub Dead-Drop Remote Code Loader

> On 2026-10-21 at 11:39 UTC a trojanized LiteLLM 1.107.0 was published to PyPI (all seven platform wheels) and shipped in LiteLLM container images on GHCR and Docker Hub (tags v1.107.0, latest, main-latest, main-stable). The wheels drop cook.pth, cook.py and sitecustomize.py into site-packages, which run on every Python interpreter start to steal system, browser, developer, cloud, CI/CD, AI-tool and LiteLLM proxy database secrets, encrypt them with AES-256-CBC/RSA-4096 and POST them to the lookalike endpoint www.litellm.dev/healthcheck, while a detached daemon polls a GitHub dead drop (letters9813/pythonclient-test) hourly to fetch and exec remote Python code. PyPI has quarantined the release; the last safe version is 1.106.2.

- **Published:** 2026-10-21T14:20:50Z
- **Last reviewed:** 2026-10-26T20:41:54.340Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-4042
- **ID:** TL-2026-4042
- **Severity:** CRITICAL
- **Category:** SUPPLY_CHAIN
- **Status:** ACTIVE
- **Detections:** 9 · **IOCs:** 69 (full data via the Threadlinqs MCP server — Purple tier)

## Description

LiteLLM (BerriAI) is a widely deployed Python SDK and proxy/gateway that brokers calls to LLM providers and typically holds high-value provider API keys. On 21 October 2026 a malicious version, 1.107.0, was uploaded to PyPI. AISLE recorded the first malicious wheel upload at 11:39:51 UTC, flagged it at 11:43:05 UTC (3 minutes 14 seconds after upload) and had identified all seven wheels as malicious by 12:00:06 UTC. Wiz reported that LiteLLM Docker containers on GHCR and Docker Hub also included the trojanized version, affecting the v1.107.0, latest, main-latest and main-stable tags. PyPI subsequently quarantined the release (Wiz: 'quarantined on PyPI as of 1:20 UTC'), and the GitHub dead-drop repository was taken down as of 1:30 PM UTC. Aikido noted that at the time of its writing the Docker Hub image remained live. The last known-good release is 1.106.2; SafeDep additionally lists 1.107.0rc1 and 1.107.0rc2 as clean.

Injection vector: the payload exists only in the built wheel artifacts. SafeDep and Aikido found an extra maturin build directive in the wheel's pyproject.toml (`[tool.maturin] data = "cook"`) that copies a `cook/` directory into the wheel so that its contents land at the root of site-packages. The upstream GitHub tag v1.107.0 contains neither the directive nor the cook/ folder, and the sdist does not contain the three payload files, so reviewers inspecting only source, Git tags or the sdist would miss it. JFrog found the malicious wheels share ZIP timestamps and metadata with legitimate wheels, indicating injection during normal wheel construction rather than manual repacking. All analysts conclude either a compromised build/release pipeline or a stolen PyPI publishing token; the exact access path remains unknown.

Stage 1 - cook.pth / cook.py ('privcollect' stealer): cook.pth (12 bytes) contains `import cook` and is processed by Python's site module at every interpreter start, so the stealer runs inside every Python process on the host (applications, pip, IDEs, CI jobs). cook.py is a two-line wrapper of the form `exec(zlib.decompress(base64.b64decode('...')))` that unpacks ~61 KB of Python identified by JFrog as the 'privcollect' credential stealer. It runs in a daemon thread, sets `PRIVCOLLECT_ACTIVE=1` to avoid re-execution within the same process tree and writes the run-once marker `/tmp/.pc_once_72129118c59f5636c0bb` after a successful upload (the marker logic fails on Windows). Temporary artifacts `/tmp/.pc_sq_*` and `/tmp/.pc_e_*` are created during collection. Collection modules cover: system data (hostname, user, OS, IP addresses, network settings, process lists); Chromium-family browser passwords/cookies/history (Chrome, Edge, Brave, Vivaldi, Opera; DPAPI-decrypted on Windows) and Firefox logins.json/key4.db; ~/.ssh/*, GPG and TLS private keys and .pem/.key/.pfx/.p12/.pk8/.ppk files; bash/zsh/fish/PowerShell PSReadLine/cmd history; ~/.aws/credentials, Azure profiles, gcloud, ~/.kube/config, ~/.docker/config.json, GitHub CLI hosts.yml, rclone.conf, ~/.netrc; package-manager credentials (.npmrc, .pypirc, pip, Maven, Gradle, Composer auth.json, RubyGems, Cargo); FileZilla saved servers; Kubernetes service-account tokens; CI/CD secrets (GitLab runner config.toml, Jenkins initialAdminPassword and master.key, .vault-token, Terraform credentials.tfrc.json); AI developer tools (Claude Code, Claude Desktop, Cursor, Windsurf, GitHub Copilot, VS Code mcp.json, Gemini CLI, Hugging Face tokens); the process's own environment plus /proc/<pid>/environ of other processes on Linux; cloud instance metadata (AWS IMDSv2/v1 and ECS, Google Cloud, Azure via 169.254.169.254); and - LiteLLM-specific - a Prisma connection via DATABASE_URL to dump `LiteLLM_CredentialsTable` and `LiteLLM_ProxyModelTable`, which hold the LLM provider API keys managed by a LiteLLM proxy.

Exfiltration: collected material is encrypted with a per-payload random AES-256-CBC key, the key is wrapped with an embedded RSA-4096 public key using OAEP-SHA256, and the result is packed into a tar.gz containing hdr.json, data.bin and key.bin. The archive is POSTed over plaintext HTTP to `http://www.litellm.dev/healthcheck` - an attacker-controlled lookalike of LiteLLM infrastructure fronted by Cloudflare (AISLE: 104.26.10.8, 104.26.11.8, 172.67.73.104) - with headers `X-Token: XWiA8gZNa7NcX2XRoAEb` and `X-SHA256`, and User-Agent `Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0)` (Aikido).

Stage 2 - sitecustomize.py (remote code loader / RAT): Python imports sitecustomize automatically at startup. The module takes an exclusive flock() on `/tmp/remote_code_loader.lock` so only one instance runs per host, then fork()s and setsid()s into a detached daemon (PPID 1, own session, stdio to /dev/null, cwd /). Every 3,600 seconds it reads the first domain-like line from the GitHub dead drop `https://raw.githubusercontent.com/letters9813/pythonclient-test/main/domain.txt`, re-runs an embedded copy of the stealer (without the once-per-host marker), and downloads `http://<domain>/codepy`, executing it with `exec(compile(code, "<remote>", "exec"), {"__name__": "__main__"})` with no integrity verification. The attacker could therefore redirect infected hosts to new infrastructure simply by editing the GitHub file. AISLE reports the repository was created on 18 October 2026, three days before the attack; at analysis time domain.txt returned HTTP 200 with an empty body (the second stage was never armed), and the repository was removed by 13:30 UTC on 21 October.

Attribution and context: this is the second documented hijacking of LiteLLM in 2026. The first (24 March 2026, versions 1.82.7 and 1.82.8, litellm_init.pth, exfil to models.litellm.cloud and checkmarx.zone) was traced by LiteLLM to the compromised Trivy dependency in its CI/CD scanning workflow and attributed to TeamPCP (UNC6780). JFrog states that no evidence currently links the October 1.107.0 incident to TeamPCP or the earlier access path and that the incidents should be treated as separate campaigns; no source attributes 1.107.0 to a named actor. No source confirms observed victim infections. BeaconBeagle returned no C2 beacon or config matches for www.litellm.dev or its Cloudflare edge IPs. Any host or container that installed or ran litellm 1.107.0 should be treated as fully compromised: all reachable credentials, including every LLM provider key stored in a LiteLLM proxy database, must be rotated.

## MITRE ATT&CK

- T1583.001 Domains
- T1608.001 Upload Malware
- T1195.002 Compromise Software Supply Chain
- AML.T0010.001 AI Software
- T1059.006 Python
- T1546.018 Python Startup Hooks
- T1027 Obfuscated Files or Information
- T1036.005 Match Legitimate Resource Name or Location
- T1480.002 Mutual Exclusion
- T1555.003 Credentials from Web Browsers
- T1552.001 Credentials In Files
- T1552.003 Shell History
- T1552.004 Private Keys
- T1552.005 Cloud Instance Metadata API
- AML.T0055 Unsecured Credentials
- T1082 System Information Discovery
- T1057 Process Discovery
- T1005 Data from Local System
- T1560.002 Archive via Library
- T1102.001 Dead Drop Resolver
- T1048.003 Exfiltration Over Unencrypted Non-C2 Protocol
- T1585 Establish Accounts
- T1550.001 Use Alternate Authentication Material: Application Access Token
- T1016 System Network Configuration Discovery
- T1217 Browser Information Discovery
- T1071.001 Application Layer Protocol: Web Protocols
- T1573.002 Encrypted Channel: Asymmetric Cryptography
- T1041 Exfiltration Over C2 Channel
- T1078 Valid Accounts
- T1583.006 Acquire Infrastructure
- T1204.005 User Execution
- T1213.006 Data from Information Repositories
- T1528 Steal Application Access Token
- T1119 Automated Collection
- T1020 Automated Exfiltration
- T1078.004 Valid Accounts
- T1070 Indicator Removal
- T1087.004 Account Discovery
- T1526 Cloud Service Discovery
- T1105 Ingress Tool Transfer

## Sources

- [LiteLLM Compromised, Steals Credentials (Wiz Blog - Benjamin Read, Rami McCarthy)](https://www.wiz.io/blog/litellm-compromised-steals-credentials)
- [LiteLLM Hijacked Again: Malicious 1.107.0 Wheels Steal Credentials and Load Remote Code (JFrog Security Research)](https://research.jfrog.com/post/litellm-hijacked-again/)
- [Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor (SafeDep)](https://safedep.io/litellm-pypi-compromise-credential-stealer-backdoor/)
- [LiteLLM compromised: infostealer and RAT in PyPI 1.107.0 (Aikido)](https://www.aikido.dev/blog/litellm-compromised-infostealer-rat)
- [LiteLLM 1.107.0 on PyPI shipped a credential stealer (AISLE)](https://aisle.com/blog/litellm-11070-on-pypi-shipped-a-credential-stealer)
- [Security Update: Suspected Supply Chain Incident (LiteLLM - March 2026 prior compromise)](https://docs.litellm.ai/blog/security-update-march-2026)
- [LiteLLM AI Supply Chain Attack Explained (SOCRadar - March 2026 TeamPCP incident context)](https://socradar.io/blog/litellm-supply-chain-attack/)
- [BerriAI/litellm Releases](https://github.com/BerriAI/litellm/releases)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-4042
