For roughly two hours on the morning of October 21, installing the latest version of LiteLLM could hand your cloud keys, SSH keys and AI API tokens to an attacker. LiteLLM is the popular open-source Python gateway that sits between applications and dozens of large language model providers. Someone took over the project's release pipeline and published a trojanized version 1.107.0 to the Python Package Index (PyPI) and to the project's Docker images. The malicious build carried two things: an infostealer that swept the host for secrets, and a backdoor that checked in every hour for new code to run.

The project's maintainer, BerriAI, published an incident post saying the compromise has been contained. The last safe release is 1.106.2. LiteLLM's guidance is direct: anyone who ran 1.107.0 should treat that environment as compromised and rotate every credential it could reach.

The blast radius could be large. The Register reports that LiteLLM gets about 23 million downloads a week. A tool built to hold API keys for OpenAI, Anthropic and other providers was always going to be a valuable target, and this is not the first time it has been hit.

The timeline

According to LiteLLM's incident post, the pipeline was compromised at about 4:00 AM Pacific time on October 21. The sources give slightly different end times for each exposure window. They are close, but defenders checking logs should use the widest window.

  • PyPI: All seven 1.107.0 wheels went up at 11:39 UTC. The OSV malware record puts the upload between 11:39 and 11:40 UTC. LiteLLM says the wheels stayed live until 13:23 UTC. Wiz says PyPI quarantined the package at 13:20 UTC.
  • Docker Hub and GitHub Container Registry: Malicious images were published under the tags v1.107.0, latest, main-latest and main-stable. LiteLLM says the Docker Hub image index (digest beginning sha256:1bbcb1443bc9) was live from 11:46 to 14:20 UTC, while the GHCR tags were unavailable by 13:51 UTC. Wiz says the tags were removed at about 13:53 UTC.

The Docker tags matter most. Teams that pull latest or main-stable by default, including automated deployments that restart containers on a schedule, could have picked up the malicious image without anyone choosing to upgrade.

How the attackers got in

BerriAI's account, as reported by Wiz, is that the attackers used stolen GitHub CLI OAuth tokens belonging to three LiteLLM engineers. GitHub's command-line tool stores these tokens so that a developer stays signed in. With those tokens, one compromised account triggered the release and a second approved it. That detail is uncomfortable for anyone who relies on a two-person approval rule: both "people" were the attacker. LiteLLM says one of the stolen tokens belonged to a GitHub organization owner, which the attacker used to disable branch protections and force-push a change to the release workflow.

How the tokens were stolen is less clear. LiteLLM says it believes the attacker got into an internal LiteLLM deployment that was exposed to the public internet and read the tokens from its logs. It says that in some situations Claude Code embeds a user's GitHub CLI OAuth token in a response body, which can end up in LiteLLM logs wherever response bodies are logged. The company has not confirmed how the attacker got into the deployment and currently suspects a recently patched vulnerability, so treat this as its working theory rather than a confirmed finding. Separately, LiteLLM mentions an embargoed release that fixes a vulnerability scheduled for disclosure on October 27.

The source code itself was never altered, which is the clever part of the attack. LiteLLM says the official GitHub source tag for v1.107.0 was clean. The OSV record agrees that the v1.107.0 tag of BerriAI/litellm does not contain the malicious code, so it was injected at build or upload time. Wiz reports that the malicious commits came from a lookalike GitHub organization called Berri-AI, with a hyphen, and LiteLLM says the published artifacts were built from that attacker-controlled repository.

Aikido Security describes the packaging trick. The attacker abused the data directive of maturin, a build tool for Python packages, in the project's pyproject.toml. That setting tells the build to include extra files. The attacker used it to slip a cook/ directory into the wheels without touching the source repository.

What the malware does

According to the OSV record (MAL-2026-2144), every malicious wheel ships three extra files under litellm-1.107.0.data/purelib/: cook.pth, cook.py and sitecustomize.py. Both mechanisms are designed so the code runs without anyone ever importing LiteLLM.

The trigger. Python automatically processes .pth files in its package directories every time the interpreter starts. The malicious cook.pth loads cook.py, so the payload fires whenever any Python process starts in that environment, whether it is a test runner, a cron job or an unrelated script.

The stealer. cook.py unpacks and runs a compressed, encoded payload that names itself "privcollect." OSV lists what it collects:

  • Browser passwords and history
  • SSH keys and shell history
  • AWS, Google Cloud and Azure credentials, plus cloud instance metadata
  • Kubernetes, Docker, HashiCorp Vault and CI/CD secrets
  • Configuration for AI coding tools, including ~/.cursor, ~/.claude, ~/.kiro and Windsurf
  • GPG and TLS private keys
  • Package publishing and Git credentials (.npmrc, .pypirc, .git-credentials)
  • Environment variables, where many LLM API keys live

The data is encrypted with an embedded RSA-4096 public key and sent to www.litellm.dev/healthcheck, a domain made to look like it belongs to the project. The Register describes the encryption as AES-256-CBC combined with RSA-4096. Because the data is encrypted, network logs are unlikely to show what was taken.

The backdoor. sitecustomize.py is another file Python loads automatically at startup. OSV says it detaches into the background and, once an hour, fetches a list of domains from a file on a GitHub account named letters9813, then downloads and runs code from those domains. That turns a one-time theft into ongoing remote access. Aikido reports that GitHub has taken down the attacker's dead-drop repository. A machine that ran the backdoor should still be treated as one that may have received and executed arbitrary follow-on code.

Wiz notes that the payload shows signs of being written with help from an LLM. That observation doesn't change the response.

Not the first time

Aikido calls this "LiteLLM compromised again," and the OSV record explains why. The MAL-2026-2144 entry (alias PYSEC-2026-2) was first published on March 24, 2026. It also covers earlier malicious versions, 1.82.7 and 1.82.8, which used the same .pth trick. Source notes in the record say that earlier compromise came through a Trivy security scan running in a GitHub workflow. The Register, citing CloudSEK, reports that the March incident exposed more than 2,500 organizations. That figure comes from CloudSEK's research, not from LiteLLM.

Two pipeline compromises in seven months, through two different routes (a CI workflow in March, stolen developer tokens in October), show how exposed the project's release process has been. None of the sources say the two incidents are linked. The Register said BerriAI did not respond to its request for comment.

What It Means for Defenders

Who is affected. You are affected if any machine, container or CI job installed LiteLLM 1.107.0 from PyPI, or pulled the Docker Hub or GHCR image tagged v1.107.0, latest, main-latest or main-stable, during the windows above. To be safe, treat 11:39 to 14:20 UTC on October 21 as the exposure period. Per OSV, versions 1.106.2 and the release candidates 1.107.0rc1 and rc2 are not affected. LiteLLM says its enterprise private registry was not affected.

Find it.

  • Check lockfiles, dependency manifests, CI build logs and container image histories for litellm==1.107.0 or the image digest beginning sha256:1bbcb1443bc9.
  • Remember transitive installs. LiteLLM is often pulled in by other AI frameworks and agent tools, so a project that never lists it directly may still have it.
  • On hosts, look for cook.pth, cook.py or an unexpected sitecustomize.py in Python package directories, and for the marker files /tmp/.pc_once_72129118c59f5636c0bb (or any /tmp/.pc_once_*) and /tmp/remote_code_loader.lock. Finding one confirms exposure, but not finding one does not prove a host is clean, since container and temp-file cleanup can remove the markers.
  • In network logs, look for traffic to litellm.dev (including www.litellm.dev) and for hourly requests to raw.githubusercontent.com followed by HTTP requests for a /codepy path.

Fix it. Pin LiteLLM to 1.106.2. Uninstalling the package does not undo what the stealer already sent, and the backdoor may have run other code, so rebuild affected hosts and containers from known-good images instead of trying to clean them in place.

Rotate everything. Both LiteLLM and OSV say every credential reachable from an affected environment should be rotated. In practice that means cloud access keys and service-account keys for AWS, GCP and Azure, every LLM provider API key, SSH keys, Kubernetes service tokens and kubeconfigs, Vault tokens, CI/CD secrets, PyPI and npm publishing tokens, Git credentials, GPG and TLS keys, and passwords saved in browsers on developer workstations. Then review cloud audit logs for activity using those credentials since October 21. LiteLLM suggests checking CloudTrail for GetCallerIdentity calls from the instance role around install time, then for use of the role's credentials from outside your infrastructure; Wiz reports it observed attackers validating harvested AWS instance-role credentials this way, starting about 4.5 hours after exfiltration. Stolen package-publishing tokens deserve priority, since they could let an attacker publish malicious packages to other projects.

Harden for next time.

  • Stop deploying mutable tags such as latest in production. Pin images by digest and packages by version and hash, and update deliberately.
  • Treat GitHub CLI and personal OAuth tokens on developer machines as production credentials. Make them short-lived and narrowly scoped, and keep them off servers that are exposed to the internet.
  • Remember that two-person release approval does not help if both accounts can be taken over the same way. Require phishing-resistant MFA or hardware-backed signing for release steps, and verify that published artifacts match the tagged source.
  • Never leave an internal AI gateway reachable from the internet. LiteLLM's own suspected root cause is an internal deployment that was exposed to the public internet.

For organizations working toward CMMC, the incident is a useful test of supply-chain risk management and incident response. If a developer laptop or CI runner in your environment pulled 1.107.0, can you name every secret it held within an hour? If you can't, start building that inventory now.

Sources