High

One Unrevoked Key Let Attackers Hijack LiteLLM’s Release Pipeline

LiteLLM says a master key leaked on GitHub in May and never revoked let an attacker steal maintainer tokens and ship a backdoored 1.107.0 to PyPI, Docker Hub and GHCR.

The poisoned LiteLLM 1.107.0 release didn’t start with a clever exploit. It started with a key nobody revoked. LiteLLM’s maintainers say a master key for their Agent Platform was accidentally committed to a public GitHub repository on May 27, and while the commit was force-pushed over, that one key was never rotated, The Hacker News reports. Five months later an attacker used it to grab a GitHub organization owner’s token, steal maintainers’ tokens, and push a backdoored LiteLLM to PyPI, Docker Hub and GHCR. The full timeline is in LiteLLM’s postmortem.

For defenders

The chain: On Oct. 10 the attacker queried the Agent Platform API with the leaked key, which returned a GitHub CLI OAuth token for an org owner that was never scoped down: T1528 (Steal Application Access Token). Using it, they ran CI workflows in BerriAI repos that posted secrets, including two maintainers’ tokens, to webhook.site, then deleted the runs. That’s T1677 (Poisoned Pipeline Execution) and T1567.004 (Exfiltration Over Web Service: Exfiltration Over Webhook). On Oct. 21 they disabled branch protection, pointed the release workflow at a lookalike fork, Berri-AI/litellm, and used one stolen token to trigger the release and another to approve it. A rule that normally tied approval to a locked-down office device had been relaxed earlier that week. Then they deleted run records and force-pushed main.

What shipped: litellm==1.107.0 on PyPI (seven wheels) and the v1.107.0, latest, main-latest and main-stable image tags, live for about two hours before PyPI quarantined the package and the tags were repointed. Upwind’s Lidor Machluf raised the alarm. No CVE has been assigned. This is T1195.002 (Supply Chain Compromise: Compromise Software Supply Chain).

The payload: per Microsoft’s analysis, cook.pth, cook.py and sitecustomize.py land in the Python library path and run on any Python start, even if LiteLLM is never imported: T1546.018 (Event Triggered Execution: Python Startup Hooks). They collect SSH keys, Git and registry tokens, environment variables and LiteLLM’s stored provider credentials, and on Unix an hourly loader fetches remote code. Microsoft warns that uninstalling the package leaves those startup files behind.

Network
www[.]litellm[.]dev (hxxp://www[.]litellm[.]dev/healthcheck, exfil POST)
69.48.229[.]143
hxxps://raw[.]githubusercontent[.]com/letters9813/pythonclient-test/main/domain.txt (C2 dead drop)
webhook[.]site/65a42464-3cfa-4b02-a18c-17a6d7b86f37
webhook[.]site/4da03473-a3e7-4dc2-a087-9c564b4208e1

Host
cook.pth  SHA-256 7f191632e7320705d154b85204f1ae546b543acbd7e8861229b76f5042b92bdb
cook.pth  SHA-256 84dc8c82c0a4a4a62552ef826b49fcc86d1a5c4a5d0f2c06665723f93d129d7d
cook.py   SHA-256 9dd0a3926f96a37eb86cf1ee2310d9be93139cc4ebef3ef9e2efe9531390be25
sitecustomize.py  SHA-256 34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa
/tmp/remote_code_loader.lock
/tmp/.pc_once_72129118c59f5636c0bb
Temp directories starting with .pc_e_
Workflow file .github/workflows/cache.yml, commit “ci: bump cache config”

What it means for you

LiteLLM is a popular piece of plumbing that lets apps talk to AI models such as OpenAI’s and Anthropic’s. If you don’t build or run AI software, there’s nothing for you to do. The broader lesson applies to anyone who manages passwords for a team: deleting a leaked password from where it was posted isn’t enough. You have to change it, or it keeps working for whoever copied it.

Do this now

  1. Search lock files, pip and uv caches, internal mirrors and container images for LiteLLM 1.107.0 and the floating tags above. Pin images by digest, not tag.
  2. If it ran anywhere, rebuild that system from a clean image and confirm cook.pth and the rogue sitecustomize.py are gone. Uninstalling the package isn’t enough.
  3. Rotate every credential that system could reach: AI provider keys, cloud, CI and registry tokens, SSH keys and database URLs. Revoke active sessions, too.
  4. Audit your own repos for secrets that were “removed” but never revoked, and scope GitHub tokens to the minimum.

More from the Roundup