JOURNAL
Four Hours: How LiteLLM’s Supply Chain Got Hit, and Where the Tokens Leaked
LiteLLM's own incident report traces a supply-chain compromise back to three stolen GitHub OAuth tokens, one of which leaked because Claude Code embedded it in a logged response body. The timeline, the blast radius, and what to check if you pulled v1.107.0.

On this page
10:08:29 UTC, October 21. That’s the exact second someone used a stolen GitHub CLI OAuth token to disable branch protection on LiteLLM’s repository, according to the timeline LiteLLM itself published. By 14:20 UTC, roughly four hours later, the cleanup was done: the malicious package pulled from PyPI, the Docker Hub tags repointed, the compromised tokens revoked. Four hours is actually a fast response. It’s just that the four hours before 10:08 are the ones that mattered.
What got compromised: every one of the seven PyPI wheels for litellm==1.107.0, plus the v1.107.0, latest, main-latest and main-stable tags on both Docker Hub and GHCR. If you pulled LiteLLM through any of those channels on October 21, you pulled the malicious build, full stop. LiteLLM’s own numbers, cited from ClickPy download stats, put the malicious version’s download count at roughly 49,000 before it came down.
The attacker used three compromised GitHub CLI OAuth tokens, including one belonging to an org owner, to disable branch protection and force-push a modified release workflow. That workflow pointed at a lookalike repository, a near-identical fork sitting one hyphen away from the real org name, and pulled the malicious code from there. Ten commits went in, stacked to look unremarkable, including one that added a single throwaway line, data = “cook”, to pyproject.toml. The actual payload sat in a detached sitecustomize.py loader that checked an hourly GitHub-hosted pointer file for instructions. That’s the part worth sitting with: the malware didn’t ship fully formed, it shipped with a phone line back to GitHub that the attacker could use to push new behavior into every machine that had already installed it, for as long as it stayed installed.
What the payload did once it had a foothold: steal credentials, then load remote-code-execution tooling on demand. Not a one-shot data grab. A standing foothold that kept taking instructions after the install finished.
How three OAuth tokens ended up in an attacker’s hands

This is the detail that should stop you mid-scroll if you use any agentic coding tool: LiteLLM’s own incident report says “Claude Code will embed a user’s GitHub CLI OAuth token into a response body, and in situations where response bodies are logged, these tokens may appear in LiteLLM logs.” Read that twice. An agentic coding assistant put a live OAuth token into the body of an HTTP response. A gateway sitting in the request path, configured with response-body logging turned on, wrote that token to disk in plaintext. The attacker didn’t phish anyone or brute-force a password. They read logs that a popular developer tool had quietly filled with credentials nobody knew were there.
I don’t think this is a LiteLLM-specific failure, and LiteLLM doesn’t frame it that way either. It’s a shape of problem that applies to any gateway, proxy or observability layer sitting between an agentic tool and the services it calls, the moment someone flips on verbose logging to debug something unrelated. The agent did exactly what it was built to do: carry a credential through a request so the next call could authenticate. The logging layer did exactly what it was built to do: capture bodies for debugging. Neither component was malicious. The combination created a token a human could exfiltrate just by reading a log file.
The lookalike-repo trick deserves its own line item on anyone’s CI/CD threat model. A workflow file that normally points at your own org can be force-pushed to point somewhere else entirely, and unless someone is diffing workflow files on every push, not just reviewing pull requests, that redirect sits there quietly doing its job. Branch protection is supposed to be the backstop against exactly this. It only works if the credentials that can disable it are harder to steal than the ones protecting your production database, and on October 21 that wasn’t true.
What to actually check this week
If you run litellm==1.107.0 from PyPI, or pulled any of those four Docker tags on October 21, assume compromise and rebuild from a clean version, not just an upgrade. Rotate every credential that container or environment had access to; a standing RCE foothold had time to read whatever was reachable, and you don’t get to assume it didn’t. LiteLLM says enterprise customers on private registries were not affected, since the compromised artifacts only ever touched the public PyPI and Docker Hub/GHCR channels, which narrows the blast radius if that’s your setup, but confirm it rather than assume it.
Separately from this specific incident, go check what your own logging configuration captures from any gateway sitting between agentic coding tools and the APIs they call. Response-body logging is a reasonable debugging default right up until the day a tool you didn’t audit embeds a credential somewhere in a body you’re capturing wholesale. Scrub tokens at the logging layer, not just at the point where a human might type one into a prompt.
The force-push happened at 10:08:29 UTC. Someone wrote down that exact timestamp because they could reconstruct it from logs. Make sure your own logs would let you do the same, for the right reasons this time.
Sources
LiteLLM: Security Incident, October 21, 2026 (primary incident report, retrieved October 28, 2026).



Discussion
Comments are reviewed before publication. Your email is kept private.