LiteLLM 1.107.0 on PyPI was a credential stealer and backdoor: what to check and rotate
A malicious LiteLLM release and Docker images went out on 21 October 2026; here is what the malware does, what researchers disagree on, and how to clean up.
· 7 min read
Written by AI from the sources linked below. How we use AI
On this page
LiteLLM 1.107.0, a release of the widely used Python gateway for calling AI models, was published to PyPI on 21 October 2026 with a credential stealer and a remote-code loader inside it. PyPI removed the release within about two hours, and the maintainers later took infected Docker images down too. Anyone who installed that exact version, or pulled the affected container tags, should treat the machine as compromised and rotate every secret it could reach.
Key points
- Only
litellm==1.107.0is affected: all seven wheels on PyPI carry the payload, as do the Docker tagv1.107.0and, for roughly three hours, the floating tagslatest,main-latestandmain-stable(StepSecurity). - The wheels were uploaded at 11:39–11:40 UTC on 21 October, and PyPI no longer served the version by 13:23 UTC, according to Mend and StepSecurity; BerriAI confirmed the infected images were removed at 14:32 UTC (StepSecurity).
- The implant installs
cook.pth,cook.pyandsitecustomize.pyintosite-packages, so it runs every time any Python process starts, even one that never importslitellm. - The last release reported clean is
litellm==1.106.2; 1.107.0rc1 and rc2 are also reported clean. - Researchers disagree on how the malicious build was made, and BerriAI's own post-mortem has not yet been published as far as we can find.
What happened
LiteLLM is an open-source library and proxy server that lets applications call many AI model providers through one interface. Mend puts its usage at more than 92 million downloads over the past month. That figure is for the whole package, not for the bad release.
According to SafeDep's timeline, the real v1.106.2 reached PyPI at 10:44 UTC on 21 October. Between 11:20 and 11:37 UTC, the malicious 1.107.0 wheels were built, and at 11:39–11:40 UTC all eight files (seven wheels and a source archive) were uploaded. StepSecurity says an infected container image was pushed at 11:48 UTC and the floating Docker tags were repointed to it; a GitHub release for v1.107.0 appeared at 11:50 UTC. The compromise was reported publicly at 12:06 UTC in issue #47826 on the BerriAI repository. Mend says PyPI quarantined the release in under two hours, with the reporter confirming at 13:23 UTC that it was no longer served.
One detail matters for anyone auditing their systems: the source archive (sdist) on PyPI contains a tampered pyproject.toml, with an extra data = "cook" line in the [tool.maturin] section, but it does not contain the payload folder. The malware is in the pre-built wheels. Installing from the sdist would not have dropped the implant, according to SafeDep and StepSecurity.
What the malware does
Both SafeDep and StepSecurity describe two components.
A credential stealer. On startup it gathers SSH and GPG keys, cloud-provider credentials, CI/CD secrets, browser passwords, shell history, tokens of AI coding tools, and environment variables. If the host runs a LiteLLM proxy with a database configured, it also dumps the provider API keys stored there. StepSecurity counts 16 categories of data. The bundle is encrypted with AES-256-CBC, the key is wrapped with RSA, and the result is sent by plain HTTP POST to www.litellm[.]dev/healthcheck. StepSecurity adds that it retries on each start until the server answers with HTTP 200, and that the litellm.dev domain was registered on 13 October 2026.
A remote code loader. A background process detaches from the terminal and, every hour, reads a domain name from a file in an attacker-controlled GitHub repository, then downloads and runs code from that domain's /codepy path. The two write-ups differ on how dangerous this stage was. StepSecurity says the file was empty at release time, so the stage was not armed, and that the loader fails silently on Windows. SafeDep says the GitHub account was deleted about two hours after release and that hosts which ran the daemon earlier may have run second-stage code; it could not recover the server address. Neither could confirm that any second-stage code was ever delivered, so the safe assumption is "unknown".
Background
This is not the first time LiteLLM has been hit. In March 2026, versions 1.82.7 and 1.82.8 were published to PyPI with a backdoor, and the Cloud Security Alliance's research note attributes it to a threat actor it calls TeamPCP. That case is separate: different versions, a different file name (litellm_init.pth) and a different attribution story. SafeDep notes that no attribution to a specific group has been established for 1.107.0, and the sources we read did not link the two incidents.
Package registries have also been a repeated target this month. We covered how OVHcloud CLI releases were swapped for a secret-stealing build earlier in October. The common pattern is that a trusted release channel is used to deliver code that runs with the permissions of a developer or CI machine.
How the release was built: where researchers differ
SafeDep reports that the v1.107.0 git tag does not contain the payload, that its pyproject.toml even declares version 1.108.0, and that the source archive matches a later main commit with five edited files. It checked 539 public GitHub Actions runs between 09:30 and 12:30 UTC and found none that published the release, and PyPI has no provenance attestation for 1.107.0. It therefore rates it "moderate to high confidence" that BerriAI's own private release pipeline built the wheels from attacker-modified source.
StepSecurity's account is different in an important detail: it says the release was built from a lookalike repository named Berri-AI/litellm (with a hyphen), where the attacker pushed ten commits between 08:56 and 10:46 UTC, and that the lookalike repository and the letters9813 GitHub account now return 404. The BerriAI issue title says the same. The two accounts can both be partly right, since a lookalike source could still be fed into the real pipeline, but we could not verify how that happened. Only BerriAI's pipeline logs can settle it.
Docker status also differs between sources. A report in the first hours said the latest and main-stable tags still pointed at the infected image at 13:44 UTC; StepSecurity says BerriAI confirmed removal of the infected images at 14:32 UTC and that all the affected tags were repointed or removed. Check your registry directly rather than trusting a cached tag.
The timeline at a glance
The figures are derived from the clock times in the sources (11:39 upload; 11:48, 11:50, 12:06, 13:23 and 14:32 UTC). The fastest part of the response was the public report, 27 minutes after upload; removal from PyPI took about 1 hour 44 minutes.
What to do if you may be affected
The steps below combine StepSecurity's and Mend's remediation guidance.
- Find everywhere 1.107.0 ran: developer laptops, CI jobs, servers and containers. Look for
cook.pth,cook.pyandsitecustomize.pyinsite-packagesand for the marker files/tmp/.pc_once_72129118c59f5636c0bband/tmp/remote_code_loader.lock. - Stop the detached Python process that holds the lock file, delete the files (and their
__pycache__copies), then installlitellm==1.106.2. - Rebuild containers from a clean image pinned by digest instead of cleaning an infected one in place. Purge cached copies of 1.107.0 from internal mirrors.
- Rotate every credential the host could read: cloud keys, SSH and GPG keys, registry and CI tokens, Kubernetes and Vault tokens, and the tokens of AI coding tools. On proxy hosts, also rotate every provider API key stored in the proxy database, plus the master and salt keys.
- Block
litellm.devat DNS or egress and search network logs for it. A request to a/codepypath would mean attacker code was fetched on that host (StepSecurity).
Removing the package from PyPI does not undo an install or cancel stolen secrets.
What it means
For developers who depend on LiteLLM, the practical lesson is to pin exact versions and image digests and to avoid auto-updating a gateway that holds every model-provider key. A proxy that stores API keys for many providers is an unusually rich target: one compromised host can expose all of them. The .pth trick is also worth knowing about, because it means a malicious package can run without ever being imported.
For maintainers, the episode points at release pipelines rather than source code: the public git tag looked clean while the published artifacts were not. PyPI has no provenance attestation for the affected releases, per SafeDep, so there was nothing automatic to compare the wheels against.
What we don't know yet
- How the attacker got malicious source into the release build, and whether the pipeline, a credential or a lookalike repository was the entry point. BerriAI has not published its findings that we could find.
- How many machines installed the wheels or pulled the images in the window. No download count for 1.107.0 specifically has been published.
- Whether any second-stage code was ever delivered to infected hosts.
- Who is responsible. No group has been named for this release.
What to watch next
BerriAI's post-mortem and any change to how it publishes (for example, trusted publishing with attestations); an advisory entry in the PyPI and GitHub advisory databases; and any report of stolen provider keys being abused.
Sources
Written by
The official account of the people who run audiotale.net: announcements, conversation starters and the newsroom's drafts. Posts written with AI say so. Every other account here is a real person.
Read next
Anthropic used Claude to cut OpenSSH's pre-login attack surface and report 493 issues in 25 open-source projects
Anthropic says Claude mapped what 25 open-source projects expose by default; in OpenSSH, about a fifth of the code reachable before authentication was removed.
audiotale.net team7 min read
TeamUpdraft breach: stolen UpdraftCentral keys used to backdoor WordPress sites
Attackers who breached TeamUpdraft's website used connection keys to install hidden plugins on WordPress sites; here is how to check for the key and clean up.
audiotale.net team8 min read
OVHcloud CLI releases 0.11.0 to 0.15.0 were swapped for a secret-stealing build on GitHub: what to check and rotate
OVHcloud says a hijacked developer account replaced release binaries for about 94 minutes on 19 October; if you installed or updated the CLI then, rotate every secret on that machine.
audiotale.net team6 min read