Ai Engineering 3 min read

LiteLLM Hit Again: a Stolen-Workflow PyPI Release That Ran on Every Python Start

The official litellm 1.107.0 release on PyPI carried a credential stealer and RCE backdoor on October 21, built through LiteLLM's own signed pipeline after attackers stole GitHub credentials from an exposed internal deployment; the package lived on PyPI for under two hours.

For under two hours on October 21, the official litellm==1.107.0 release on PyPI was malicious. Per SafeDep’s analysis and LiteLLM’s own incident report, all seven wheels (Linux, macOS, Windows) installed three files into site-packages, including a credential stealer and a backdoor daemon that executed whenever any Python process started, whether or not it imported litellm. The upstream GitHub source was clean the entire time; the attack succeeded by compromising the release pipeline itself, which means the malware arrived carrying LiteLLM’s own build provenance.

The intrusion path is the lesson

Attackers obtained GitHub CLI credentials for three LiteLLM developers, believed stolen from the logs of an internet-exposed internal LiteLLM deployment, the vendor’s own product watching its own secrets go by. Using an organization owner’s token, they bypassed branch protection, repointed the private release workflow to a lookalike repository, and passed the approval gate using a second developer’s credential, so the official pipeline built, signed, and published the malicious artifacts. The only visible change in the source distribution was an injected data = "cook" line in the maturin build config, present in no public commit. This is the second major supply-chain compromise of LiteLLM this year, after the TeamPCP PyPI attack we covered in March, and the escalation is qualitative: last time the package was malicious, this time the trust chain was.

What the malware harvested

The stealer, cook.py loaded via a cook.pth file, was comprehensive to the point of being a curriculum: SSH keys, shell history, AWS/Azure/GCP/Kubernetes/Docker/GitHub credentials, CI/CD secrets from GitLab, Jenkins, Vault, and Terraform, browser password stores, GPG and TLS keys, AWS instance metadata, and, pointedly, AI developer tool tokens (Claude, Cursor, Copilot) plus LLM provider keys from LiteLLM proxy databases. Exfiltration was AES-256 encrypted with an RSA-4096-wrapped key, POSTed to a lookalike domain with a custom token header. The backdoor, sitecustomize.py, forked a detached daemon that checked a GitHub-hosted text file hourly for a server address and executed downloaded code, meaning the attacker could retarget every infected host by editing one file; the account was deleted about two hours after upload, disabling the C2, but SafeDep could not recover whatever second-stage code ran before that.

Incident response, and the industry bill

The containment timeline was genuinely fast: malicious wheels uploaded 11:39 to 11:40 UTC, removed by PyPI at 13:23, Docker Hub and GHCR tags cleaned or repointed by 14:20. But the exposure window defines the cleanup: anyone who installed 1.107.0 in that window should treat every credential category above as stolen and rotate, check for the listed IOC files and the PRIVCOLLECT_ACTIVE=1 environment variable, review network logs for the lookalike domain, and assume any host that ran the daemon before 13:40 UTC may carry unknown second-stage code. The structural takeaway lands on every team shipping SDKs in the AI ecosystem: this month’s $25-per-breach agent campaign showed attacks getting cheaper, and this incident shows the trusted channel itself as the target. Harden the release workflow like production, because it is: require hardware-key signing approvals, keep release credentials off internet-exposed deployments, and treat a build config line appearing in the sdist but no commit as the loudest possible alarm.

Get Insanely Good at AI

Get Insanely Good at AI

The book for developers who want to understand how AI actually works. LLMs, prompt engineering, RAG, AI agents, and production systems.

Keep Reading