On October 21, 2026, a trojanized version of LiteLLM, the widely used open-source gateway for accessing AI models, was published to PyPI and Docker Hub by the project’s own release pipeline. LiteLLM’s root-cause analysis, published October 23, traces it back to a mundane mistake: an administrative key pushed to a public repository in May, deleted from the file but never revoked. Five months later, that key gave the attacker a GitHub organization owner’s token, and from there the release pipeline. It is a direct lesson for every team deploying AI agents that hold credentials.
- A master key for an internal agent platform, exposed on May 27, 2026 in a public GitHub repository, was never revoked.
- On October 10, the attacker used it to retrieve an organization owner’s GitHub CLI OAuth token, then exfiltrated CI secrets and the tokens of two more maintainers.
- On October 21, the attacker overrode branch protection and published
litellm==1.107.0(7 PyPI wheels) plus compromised Docker images. - The malicious code runs every time Python starts, even without importing LiteLLM, and steals cloud credentials, SSH keys, CI secrets, AI provider API keys and AI coding tool configurations.
- Any host that installed 1.107.0 must be treated as compromised: uninstalling the package is not enough.
The attack chain
LiteLLM calls its October 23 analysis “the canonical source of truth”. It supersedes the provisional explanations in the October 21 incident notice. The chain unfolds in seven steps.
| Date (UTC) | Step |
|---|---|
| May 27, 18:53 | An opencode.json file containing an admin key to the LiteLLM Agent Platform is committed to the public LiteLLM-Labs/lite-harness repository. It is deleted three hours later but remains in history, and the key is not revoked. |
| October 10, 21:13–21:28 | The attacker calls the agent platform API; an agent listing request returns an organization owner’s GitHub CLI token. |
| October 10, 22:11–22:14 | Workflows pushed to temporary branches post CI secrets (including GH_TOKEN and RELEASE_PLEASE_TOKEN) to a webhook.site endpoint, then the runs are deleted. |
| October 12 | Secrets from several private repositories are exfiltrated the same way. |
| October 21, 10:08 | A release-workflow change, rejected by branch protection, is forced through with the owner’s token. It allows building from the lookalike fork Berri-AI/litellm. |
| October 21, 11:11–11:47 | The production approval gate is passed with a second maintainer’s token; seven 1.107.0 wheels, then Docker Hub and GHCR images, are published. |
| October 21, 11:53–11:54 | Run records are deleted with a third maintainer’s token. |
| October 21, 12:06 → 14:20 | An Upwind Security researcher reports the compromise; PyPI quarantines the package by about 13:23 and Docker tags are removed or repointed at 14:20. |
Why a single key was enough
LiteLLM Agent Platform is an experimental project for self-hosted cloud agents that open pull requests. To do so, it held not a narrowly scoped token but the GitHub CLI OAuth token of an organization owner. According to LiteLLM, such tokens are unscoped, issued post-2FA and not subject to the re-authentication required for sensitive actions. Compromising the agent therefore meant obtaining owner rights.
Two other factors made things worse. The release workflow had been changed to accept an arbitrary source owner, enabling a build from a lookalike fork. And the release approval rule had been relaxed that very week: any two engineers could approve, instead of a dedicated account tied to a physical device.
Payload analysis
According to Corgea’s analysis, the attacker added a cook directory to the package build data. The wheels thus installed three files at the site-packages root: cook.pth, cook.py and sitecustomize.py. The sdist and the official source tag stayed clean, which kept the change out of sight in the code.
Execution and persistence
Python executes the .pth file at every interpreter start: the stealer runs even if LiteLLM is never imported. sitecustomize.py also launches a detached daemon (lock file /tmp/remote_code_loader.lock) that, every hour, fetches a hostname from a GitHub file, downloads Python code and executes it. No second stage has been observed so far.
What gets stolen
Browser passwords and cookies, SSH, GPG and TLS keys, AWS, GCP and Azure credentials (including via metadata services), Docker and Kubernetes secrets, CI configurations, Vault tokens, package registry credentials, environment variables and AI coding tool configurations. Specific to LiteLLM: the code queries the proxy’s credentials table, which holds model provider API keys. Data is encrypted (AES-256 and RSA-4096) and sent to litellm.dev, a lookalike of the legitimate litellm.ai.
Why it matters
LiteLLM sits at the heart of AI architectures: by design, it concentrates the API keys of every model provider an organization uses. Compromising it yields a full keyring. But the lesson goes beyond this project. An AI agent acting on your repositories holds credentials, and those credentials become the target. An oversized token handed to an experimental agent was enough to turn a forgotten configuration leak into a software supply chain compromise.
And deleting a file revokes nothing. A secret pushed to a public repository must be considered compromised from the first second.
MITRE ATT&CK view
The sources do not provide an ATT&CK mapping. The table below is an indicative Defensy reading based on the behaviors described.
| Technique | Observed behavior |
|---|---|
| T1593.003 — Search Open Websites/Domains: Code Repositories | Admin key recovered from a public repository’s history |
| T1078 — Valid Accounts | Use of the master key, then maintainer tokens |
| T1528 — Steal Application Access Token | Theft of the GitHub CLI OAuth token and CI secrets |
| T1567.004 — Exfiltration Over Webhook | CI secrets posted to webhook.site |
| T1070 — Indicator Removal | Deletion of workflow runs |
| T1195.002 — Compromise Software Supply Chain | Release of 1.107.0 through the official pipeline |
| T1546 — Event Triggered Execution | Execution at every Python start via .pth and sitecustomize.py |
| T1552.005 — Cloud Instance Metadata API | Queries to cloud metadata services |
Recommendations
- ImmediateCheck for exposure to 1.107.0
Look for
Version: 1.107.0in installed metadata, forcook.pth,cook.pyandsitecustomize.pyin site-packages, and for/tmp/remote_code_loader.lock. Review images pulled on October 21 with thelatest,main-latestormain-stabletags. - ImmediateTreat affected hosts as compromised
Isolate them, stop the loader, and rebuild environments and images from clean inputs, pinning a verified version (1.106.2 or a release LiteLLM confirms as clean) and images by digest.
- ImmediateRotate every exposed secret
AI provider keys stored in the proxy, cloud, Kubernetes, CI, registry, SSH and AI tool credentials. Review CloudTrail and equivalent logs from October 21, 11:39 UTC onward, and outbound traffic to
litellm.dev. - Short termReduce AI agent privileges
Give each agent a dedicated service account and least-privilege tokens, never an administrator’s personal token. Inventory the credentials held by your agents and automation platforms.
- Short termRevoke first, clean up later
Enable secret scanning at the source (push protection) and formalize a rule: any exposed secret is revoked immediately, even if the commit was deleted.
- Medium termHarden your own release pipeline
Prevent admins from bypassing branch protection, hard-code the source repository in release workflows, verify provenance and diff package contents against the previous release (alert on any new
.pth). - Medium termPin dependencies
Use lockfiles with hashes and digest-referenced images rather than floating versions and tags.
Nothing about this incident is exotic: a forgotten secret, an overpowered token, a poorly isolated AI agent. That is exactly why it should worry you. AI agents are privileged identities and must be governed as such.
Our Secure AI Adoption offering helps you scope the rights and secrets of your agents and LLM gateways. Our SOC, Detection & Response team can support you with compromise hunting and secret rotation.
- The attack chain behind the v1.107.0 LiteLLM releaseLiteLLM — O. Jensen, M. Wang — October 23, 2026
- LiteLLM 1.107.0 PyPI and Docker compromise (cook.pth, sitecustomize)Corgea — October 22, 2026, updated October 24
- The Unrevoked Key: Agent Credential to LiteLLM Release HijackCloud Security Alliance Labs — October 2026
- Leaked LiteLLM master key let attackers hijack the release pipelineThe Hacker News — October 2026
