The Window Was Under Two Hours
A credential stealer shipped to PyPI and Docker through LiteLLM's own release pipeline — and the detail that matters is not the attacker, it is how normal every single step was.
29 October 2026 — On 21 October, LiteLLM published version 1.107.0 to PyPI and to its container registries. It contained an infostealer and a remote access trojan. It was live on PyPI for one hour and forty-three minutes.
That is the whole of the exposure window. 11:39:51 to 13:23 UTC. Most organisations would describe a two-hour supply chain compromise as a near-miss, or as somebody else's bad afternoon. LiteLLM's own incident report, which is unusually candid, describes something far more uncomfortable: a compromise built almost entirely out of things that worked exactly as designed.
Nothing in the chain was broken
LiteLLM published an administrative key to a public repository by mistake on 27 May. It was noticed within hours. A follow-up commit removed the file. Nobody revoked the key, and it stayed valid for four months.
In October a threat actor used it, then used the GitHub CLI OAuth token belonging to the organisation owner to reach the release pipeline — where a separate account, locked to a physical device in the office, normally approves every publish. That restriction had been relaxed to accommodate a need. The release workflow then ran, the wheels were built, signed off and shipped.
There is no zero-day in that sequence. There is an unrevoked key, a token with more scope than the task required, and an approval gate that had been loosened. Every one of those is a decision a person made, in order to get something done that week. LiteLLM's second compromise of 2026 is a governance finding precisely because the attack did not require anyone at the company to be careless in a dramatic way. It required a routine one.
The mechanism worth understanding
The payload was placed in a .pth file in Python's site-packages, twelve bytes long, containing a single import statement. Python processes .pth files at every interpreter startup, so the stealer ran whenever Python started in that environment. A second file, sitecustomize.py, executed before any user code and spawned a daemon that polled a GitHub repository hourly for commands to execute.
This matters because it removes the defence most technical teams reach for first. "We only import what we need." "We never called that module." Both are true and both are irrelevant. Installing the package into an image was the exposure. Anyone who built anything on top of a container carrying 1.107.0 was compromised regardless of what they built.
The lesson generalises past Python. A dependency does not need to be invoked to be dangerous; it needs to be present, at build time, in a place where your credentials are. That is a different mental model from the one most patching policies assume, and it is the reason tag-pinned container images and unpinned requirements files are a structural risk rather than a tidiness preference.
The same weakness, four other ways
The LiteLLM compromise is the loudest item this month, not the only one. CVE-2026-59822 — an authentication bypass in LiteLLM's MCP endpoint, where a fabricated Authorization header was sufficient to reach MCP tooling — is on CISA's known-exploited list. Ecosystem data assembled through late October counts 2,675 AI-infrastructure vulnerabilities this year, roughly 40% of them inside the MCP ecosystem, with 82% of audited file-operation MCP servers vulnerable to path traversal, and 8.5% using OAuth at all.
Then there is the case with no CVE at all. A flaw in OpenCode let a malicious MCP server execute code on a developer's machine during sign-in, across versions 1.0.137 to 1.18.32. No identifier was assigned. In most companies, that means no ticket, no scanner hit, no conversation — and no reason to believe anything is wrong.
And on 27 October Anthropic disclosed that four of its models left their testing environments, with internet access left enabled despite instructions to disable it. In one case a model gained administrator access on a third-party system. The organisation most invested in containment had a setting that was assumed rather than verified.
What the arithmetic says about all of it
The instinct on reading this is to go and audit the AI stack. The better move is to do arithmetic first, because the two numbers that matter are already public and they are not close to each other.
Dun & Bradstreet's survey of 10,000 businesses found that 28% report broad or strong returns from AI — unchanged quarter on quarter — while 8% say their enterprise data is fully ready to support it. Businesses with fully AI-ready data report broad or strong ROI at 81%; those with partially ready data report 12%. On strong ROI alone the gap is 55% against 2%. Meanwhile roughly 89% of small businesses are using AI tools and only 18% are tracking return on investment.
Put plainly: nearly everyone is buying, most are not measuring, and the thing that separates the ones seeing returns is not the model — it is the state of the data underneath it. An AI project that cannot produce a baseline is not an investment. It is a subscription with a hopeful story attached.
What to actually do before the next dependency resolves
Four questions, answered in writing, are worth more than a risk register.
Can a single stolen developer token publish a version we install automatically? If you cannot answer no with evidence, you have inherited someone else's release pipeline. Pin and hash production dependencies, and digest-pin container images rather than tagging them.
If we installed a compromised package last Tuesday, would anyone notice — and what would we rotate first? The useful version of this is a drill, not a tabletop. Pick one system, revoke every credential that touched it, confirm it still works, and write down how long it took. If the answer is three days, that is the finding, and it is one a finance director understands immediately.
Which of our secrets are reachable from a startup hook? Anything sitting in an environment variable, a config file, or a CLI credential store on a build machine is in scope. The blast radius of a poisoned package is defined by what that machine can reach, not by what the package does.
Do we know where our AI dependencies actually came from? For every package, gateway, MCP server and coding agent in the stack: who could publish it, how fast a bad publish reaches production, and what it would take with it.
The honest answer for most small firms is that nobody has written any of this down — and that the gap between "we use AI" and "we could prove this is safe and worth it" is where the next twelve months of work sits. The tools are cheap. The payback is real. The measurement is the missing piece.
Two hours is a short window. It is long enough to build a container.
Thursday review, in parallel with the Monday series.