[tool.maturin]
data = "cook"
On October 21, 2026, at 11:39:51 UTC, the open-source LLM gateway LiteLLM pushed official release 1.107.0 to PyPI. In the source tree’s pyproject.toml, only a single innocent-looking configuration line had been added. Yet within the next two hours, that change transformed unpinned production deployments into credential harvesting beacons. The trust boundary of AI infrastructure has collapsed from auditing upstream source code to defending build credentials—and the tool that handed the release keys to attackers was none other than the developer’s daily AI coding assistant.
A 12-Byte Hook Takes Over the Python Runtime Without an Explicit Import
litellm==1.107.0 survived on PyPI until 13:23 UTC, a window of roughly two hours. All seven published wheels spanning Linux, macOS, and Windows carried the malicious payload. Simultaneously, four key Docker tags on Docker Hub and GHCR—v1.107.0, latest, main-latest, and main-stable—were overwritten. From 11:46:56 to 14:20 UTC, these tags uniformly pointed to the poisoned container image sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e. Any automated CI/CD pipeline pulling unpinned images or packages pulled a live backdoor straight into production.
The malicious code was embedded into the wheel’s purelib/ directory using Maturin’s data = "cook" directive. Once installed, the package dropped three artifacts into site-packages: a 12-byte cook.pth, a 22,252-byte cook.py, and a 25,509-byte sitecustomize.py. The public BerriAI/litellm repository never contained a cook/ directory, nor did the source distribution archive contain these files. Security audits that rely purely on reviewing public GitHub commits proved completely blind to build-time injection.
cook.pth contains just a single line: import cook. Under Python’s standard .pth mechanism, the interpreter executes lines beginning with import upon startup. In the same directory, sitecustomize.py acts as another global hook automatically evaluated at startup, forming a dual-insurance execution chain alongside the compressed payload in cook.py. The payload completely bypasses application import chains: even if a host never executes import litellm, running pip or launching an IDE language server triggers the backdoor immediately.
Figure: File injection and dual-payload execution chain of the poisoned LiteLLM 1.107.0 package. Source: SafeDep (Supply Chain Security Analysis Report)
16 Harvester Modules Target AI Toolchains and Gateway Databases
The first-stage payload cook.py packed 16 dedicated credential harvesting modules, turning the victim host inside out. It began by reading ~/.ssh/* private keys and shell histories, decrypting stored passwords from Chromium and Firefox via DPAPI or system master keys. It systematically swept credential configurations across AWS, Azure, GCP, ~/.kube/config, Docker, gh, HashiCorp Vault, and Terraform. It queried AWS IMDS endpoints (probing IMDSv2 before falling back to IMDSv1) and traversed /proc/<pid>/environ across running processes. The payload was meticulously tailored against the typical workstation of a modern cloud-native engineer.
The most telling fingerprint of the attacker’s intent lay in two specialized modules: ai_devtools and db_litellm. The ai_devtools module targeted 17 distinct AI developer tools, scraping credentials for Claude Code, Claude Desktop, Cursor, Windsurf, GitHub Copilot, VS Code’s mcp.json, Gemini CLI, Codex, Continue, Aider, Zed, and Hugging Face. Meanwhile, db_litellm parsed DATABASE_URL to dump the gateway database in full, exporting LiteLLM_CredentialsTable and LiteLLM_ProxyModelTable. An AI gateway is inherently the credential hub for an enterprise’s LLM consumption. Compromising a single LiteLLM proxy instance yields every upstream model API key connected behind it.
Stolen credentials were encrypted with an ephemeral AES-256-CBC key, enveloped via RSA-4096 OAEP using an embedded public key, and bundled into a tar.gz archive transmitted to www.litellm.dev/healthcheck with the header X-Token: XWiA8gZNa7NcX2XRoAEb. The second-stage payload in sitecustomize.py locked /tmp/remote_code_loader.lock, daemonizing via fork() and setsid(). Every 3,600 seconds, it polled letters9813/pythonclient-test/domain.txt on GitHub to re-run harvesting and dynamically fetched and executed remote code from /codepy. GitHub suspended letters9813 around 13:40 UTC, but machines running the payload had likely already executed stage two. Combined with the lookalike domain litellm.dev, standard network monitoring failed to detect the egress anomaly in time.
Three Stolen Keys Bypass Approval Gates as Hardened Pipelines Sign Poisoned Wheels
Following a security incident in March, the LiteLLM team had significantly hardened their release pipeline. They migrated build workflows to private repositories, enabled Trusted GitHub Publishers, locked immutable Docker tags, and mandated container image signing. In theory, no unauthorized outsider could modify release automation or forge official cryptographic signatures.
Yet logs from October 21 tell the story of a break-in executed with legitimate keys. At 10:08:29 UTC, GitHub branch protection rules rejected an unreviewed pull request modifying the release workflow. Just five seconds later at 10:08:34 UTC, the attacker leveraged an organization-owner GitHub CLI token to force-disable branch protection and pushed commit 9cf97e935aeaf791b9c8db224a2bb3ee156134ce. At 10:46:39 UTC, the altered workflow fetched commit 20535d8fa from the typosquatted repository Berri-AI/litellm (differing by a single hyphen from the legitimate BerriAI) and passed pre-release checks. At 11:11:18 UTC, a second developer credential approved the production release gate. After poisoned artifacts were distributed at 11:53 UTC, a third credential wiped workflow run logs across production and pre-release pipelines. When attackers hold three legitimate high-privilege credentials, automated cryptographic signing and approval gates do not prevent supply chain attacks—they stamp official authenticity onto malicious builds.
Figure: Official security advisory from LiteLLM detailing the privileged credential compromise of their release pipeline on October 21. Source: LiteLLM (Security Postmortem)
Claude Code Leaked Tokens into Response Bodies, Making Gateway Logs a Privilege Escalation Springboard
How were three core maintainers’ GitHub credentials stolen in the first place? LiteLLM’s official postmortem surfaced a crucial architectural detail: under specific conditions, Claude Code echoes the user’s GitHub CLI OAuth token in its API response body. When an AI gateway is configured to log raw HTTP response bodies, those high-privilege bearer tokens are committed directly to disk. The team subsequently identified an obscure internal LiteLLM instance exposed directly to the public internet, concluding that attackers exploited a recently patched vulnerability to breach the instance and harvest the logged GitHub CLI tokens.
This nested leak sparked intense debate across the security community. Critics of AI assistants argued that local agents hold excessive host access privileges, and leaking gh tokens into conversational response payloads violates basic principles of least privilege and data sanitization. Infrastructure defenders countered that exposing any gateway logging raw response bodies to the public internet represents a severe operational misconfiguration. Both perspectives underline the same engineering reality: developers use AI assistants to write gateway code, while the assistant dumps root keys into the gateway’s logs. The recursive loop of AI dev tools dramatically expands the blast radius of a single misstep.
Step Zero of Remediation: Do Not Run pip, and Pin Every Dependency
For teams that inadvertently installed 1.107.0, the official remediation guide starts with a counterintuitive directive: do not run pip install to fix it. Because pip is itself a Python process, running it triggers cook.pth and sitecustomize.py all over again. The correct remediation procedure requires manually deleting cook.pth, cook.py, sitecustomize.py, and the __pycache__ directories directly from site-packages, then terminating any orphaned daemon processes holding /tmp/remote_code_loader.lock. Only after files and processes are cleaned should systems roll back to 1.106.2 or rebuild containers and virtual environments from scratch.
Removing backdoor files merely stops the bleeding; the critical priority is exhaustive credential rotation. The advisory warned: “If 1.107.0 ran on an internet-connected host, you must assume exfiltration succeeded.” Container reboots or /tmp wipes purge lockfiles, but the absence of an active lockfile does not imply safety. Teams must rotate host IAM roles, process environment variables, DATABASE_URL passwords, and every single LLM provider API key stored in the proxy database, while auditing AWS CloudTrail for unusual GetCallerIdentity calls around the installation timeframe. Clean releases include 1.106.2, 1.107.0rc1, 1.107.0rc2, and pinned installations of litellm-proxy-extras==0.4.110—only unpinned deployments bore the brunt of this two-hour blitz.
The battlefield of software supply chain security has shifted. Attackers no longer spend weeks crafting subtle malicious PRs; they fish high-value credentials out of internet-facing logs and let official pipelines sign the payload. As AI coding assistants process sensitive credentials on local developer endpoints every day, treating gateway logs as high-risk secrets and cryptographic pinning of every production dependency are the only real ways to protect the trust boundary of AI infrastructure.
Reference Links:
- SafeDep Supply Chain Security Report: LiteLLM PyPI Compromise & Credential Stealer Backdoor
- LiteLLM Official Security Advisory: Security Incident Postmortem (October 21, 2026)
- Hacker News Discussion: LiteLLM 1.107.0 Supply Chain Poisoning Incident