Executive Summary
The LiteLLM supply chain attack of 21 October 2026 shipped a working credential stealer to PyPI and to four container tags. The project carries about 23 million weekly downloads. Seven wheels, three payload files, and a direct SQL read of the two tables where an AI gateway stores its upstream provider keys. Socket flagged it seven minutes after publication. The wheels stayed downloadable for 103 minutes, the container tags for 153. Wiz watched stolen AWS role credentials get tested against model listing endpoints four and a half hours later.
It is the second time in seven months that this project’s release path was driven by someone else. March came through a compromised Trivy dependency and the answer was a rebuilt pipeline. Today came through three developer GitHub accounts holding stolen CLI tokens, one to start the release workflow and another to approve it. The verdict is uncomfortable. The component built to concentrate credentials is now the highest value target in the AI stack, and it still ships like an ordinary library.
The dangerous artifact in AI infrastructure today carried no model and no weights. It carried a 12-byte file telling a Python interpreter to import a credential stealer at startup, and it sat inside a release of the gateway whose job is to hold every provider key a company owns.BerriAI pushed it to PyPI that morning. Socket flagged the wheels seven minutes later and PyPI pulled them. Four tags on GHCR and Docker Hub, including latest and main-stable, pointed at the malicious index for over two hours. A deployment following a floating tag picked it up without asking for 1.107.0.
The hook fires at interpreter start, so checking for it re-runs it
cook.pth is twelve bytes and its entire content is an import statement for cook. Python processes executable lines in .pth files while initialising the site module, then tries to import sitecustomize. Both files landed at the root of site-packages, outside the package directory, so neither needs your application to import litellm. Start an interpreter in that environment and the collector runs.Operators who read the warning and ran pip show inside the affected virtualenv executed the payload again. The obvious remediation was a second delivery. Downloading the wheel and reading it as a zip is safe. Running anything Python in that environment is not. Wiz calls the paired hooks the first documented case of their kind in the wild. Two entry points mean removing one leaves the other.
The key table was the prize, not the traffic
The stealer runs 16 collection modules behind individual error handlers. The one that matters reads the proxy’s PostgreSQL database whenever DATABASE_URL is set, selecting from LiteLLM_CredentialsTable and LiteLLM_ProxyModelTable. That is where a deployment keeps the upstream OpenAI, Anthropic and Gemini keys it proxies. The rest is ordinary, AWS instance metadata, Google service accounts, SSH and GPG keys, and credential files for Codex, Claude, Gemini and Cursor.Wiz then watched the proceeds get spent. Between 16.20 and 17.01 UTC, AWS role credentials harvested from CI runners and Kubernetes nodes were validated with GetCallerIdentity and used to list models on Bedrock. That sequence is LLM jacking, where a stolen cloud identity is worth an inference bill someone else pays.

Seven months on, the release path was still the fragile part
The March incident is what makes this one sting. LiteLLM traced it to the Trivy dependency inside its CI scanning workflow, paused releases, and returned with a pipeline it described as adding isolated environments and stronger security gates. It did not touch the thing that broke today.Today’s build was not a compromise of code. It was a compromise of the people who can trigger a release. Three engineer GitHub accounts, apparently through stolen CLI OAuth tokens. One started the project-releaser workflow and another approved it. The commits went to Berri-AI/litellm, one hyphen from BerriAI/litellm, and LiteLLM’s own post confirms the official tag holds none of the malicious files.Every artifact from that run carries build provenance, and the provenance is accurate. It names the lookalike repository as the source, which is what provenance is for. That is also why provenance answers the wrong question alone. It tells you where a build came from. Not that the place was yours. The upstream thread carries the byte-level notes, including that the proxy image’s virtualenv held the same three files.The actions that work are dull. Wiz names 1.106.2 as the most recent clean release, so pin or redeploy to it. Then rotate everything the proxy environment and database held. A token that left the building does not become safe after a downgrade. Treat any host that started Python with the wheel installed as compromised rather than patched.The questions worth asking this week are about blast radius, not LiteLLM. If your gateway held every provider key, how many systems trusted those keys without asking who was calling? If a stolen OAuth token could start a release workflow, what else in your pipeline can? And when a scanner tells you a package is bad, how do you inspect it without executing it?
Related reading. We looked at what happens after a credential walks out of a shared workspace, and at why rotating one secret after a supply chain compromise is not a rotation.
Get the next one before it is old news
Independent analysis of cloud-native infrastructure, Kubernetes and data center economics. No vendor spin.

[…] same week, a much smaller project shipped a credential stealer to PyPI in the LiteLLM 1.107.0 supply chain attack, and the lesson there was the release path. Here the lesson sits one layer lower. You inherit the […]