LiteLLM 1.107.0 on PyPI and Docker shipped a credential stealer that also takes Claude Code, Cursor, Codex and Copilot logins
Summary
On Oct 21, 2026, litellm 1.107.0, the Python library and proxy that many teams and AI tools use to talk to OpenAI, Anthropic and other model providers, was published to PyPI with malware inside it. The same payload shipped in the official v1.107.0 Docker images, and for a few hours the latest, main-latest and main-stable tags pointed at the infected image. Upwind's security research team, which reported it in LiteLLM's GitHub issue #47826, says all 7 wheels drop three extra files into site-packages so the code runs every time Python starts in that environment, even if nothing imports litellm. Upwind, StepSecurity and Aikido say the stealer collects SSH keys, cloud and CI credentials, browser passwords, the environment variables of running processes, the provider keys stored in a LiteLLM proxy database, and the logins and configs of AI coding tools including Claude Code, Cursor, Codex, GitHub Copilot, Gemini CLI and Windsurf, then sends them encrypted to the lookalike domain litellm.dev. A second file starts a background loader that can fetch and run new code from the attacker every hour; researchers say it had nothing to run yet. BerriAI, which maintains LiteLLM, is treating it as a SEV-0: PyPI quarantined 1.107.0, BerriAI removed the malicious Docker images and tells users to pin 1.106.2. In its 12:32 PM ET update BerriAI said the malicious actions came through three of its engineers' GitHub accounts, apparently via stolen GitHub CLI OAuth tokens, which it has revoked. It says it does not yet know how those tokens were taken.
Severity
Timeline
The lookalike domain litellm.dev is registered and the GitHub account letters9813 is created, per StepSecurity and Upwind.
The attacker's dead-drop repository letters9813/pythonclient-test is created, per StepSecurity and AISLE.
Ten commits that add the payload are pushed to a lookalike repository, Berri-AI/litellm (with a hyphen), on top of the real v1.107.0 code, per Upwind and StepSecurity.
BerriAI's release workflow (project-releaser) starts a run that, according to the image build records Upwind examined, builds from the lookalike repository instead of BerriAI/litellm.
The 1.107.0 files are uploaded to PyPI (11:39–11:40 UTC). AISLE says its dependency firewall flags the first wheel at 11:43 UTC. The infected image is pushed to Docker Hub at 11:48 UTC and the latest, main-latest and main-stable tags point to it, per Upwind and StepSecurity. The GitHub release v1.107.0 is published at 11:50 UTC.
Upwind's research team reports the compromise in BerriAI/litellm issue #47826 with file hashes, a decoded payload and indicators of compromise.
Upwind reports 1.107.0 is gone from PyPI and that the Docker tags still point to the infected image. At 13:50 UTC BerriAI replies that it is treating the incident as SEV-0 and that PyPI quarantined 1.107.0.
BerriAI says the malicious Docker images have been removed, that it has not yet identified or locked down how the attacker published the release, and that open-source users should pin 1.106.2 or another version published earlier. It says its private enterprise registry is not affected.
BerriAI says the malicious actions were taken through three engineers' GitHub accounts, apparently with stolen GitHub CLI OAuth tokens: one account triggered the release run and another approved it. It has revoked the tokens, removed all but one unaffected user from its GitHub organization, and removed trusted publishing links from its registries. It says it has not found the original attack vector and plans its next update at 18:30 UTC.
How it happened
According to Upwind, the 1.107.0 wheels were built by LiteLLM's normal build tooling, but from a source tree with extra attacker commits stacked on top of the release: one line added to pyproject.toml (data = "cook") tells the build to copy three files, cook.pth, cook.py and sitecustomize.py, straight into site-packages. Python runs .pth files and sitecustomize.py automatically at startup, which is why the payload fires on any Python start in that environment, including running pip. The git tag v1.107.0 itself is clean, and Upwind says the source tarball holds the edited pyproject.toml but not the payload files. cook.py is a stealer that calls itself privcollect. Upwind's decode lists what it gathers: host and network details, Chromium and Firefox saved passwords and cookies, SSH keys and shell histories, AWS, Azure, gcloud, Kubernetes, Docker and GitHub CLI credentials, package-registry tokens (.npmrc, .pypirc and others), .env files and private keys, CI and Vault secrets, cloud instance credentials, GPG and TLS keys, the environment variables of every process it can read, and the credentials and configs of AI tools including Claude, Codex, Gemini, Qwen, Cursor, Windsurf, Kiro, VS Code MCP settings and Copilot. StepSecurity's list adds Codex's auth.json, Gemini CLI OAuth credentials, Continue, Aider, Goose, opencode and others. If a DATABASE_URL is set, as on a LiteLLM proxy with a database, Upwind says it dumps the tables where the proxy stores every upstream provider key. The bundle is encrypted with an embedded public key and posted to http://www.litellm.dev/healthcheck. sitecustomize.py forks a background process that checks a file in the attacker's GitHub repository every hour and, if it names a domain, downloads and runs Python code from it. Upwind and AISLE say that file was empty when they looked, and Aikido says GitHub has since taken the repository down. On Windows, Upwind says the loader fails silently but the stealer still runs. On how the attacker got in: BerriAI says the release run was triggered and approved through three engineers' GitHub accounts using what appear to be stolen GitHub CLI OAuth tokens, and that it does not yet know how those tokens were obtained or whether the attacker still has other access. Credit where due: BerriAI answered the report within two hours, removed the images, revoked the tokens and has posted regular updates in the open. StepSecurity notes this is LiteLLM's second PyPI compromise this year; PyPI published an incident report on the first one in April.
How to check your app
- Find out whether you ever had 1.107.0, without starting Python first. Upwind warns that any Python start in an affected environment runs the payload again, and pip is Python. From a shell, look for the files and the install record: find / -path '*site-packages/cook.pth' 2>/dev/null and find / -type d -name 'litellm-1.107.0.dist-info' 2>/dev/null. On a machine you've already decided to treat as compromised, pip show litellm will also tell you the version. Check every virtualenv, Conda env, notebook server and CI image, not just your laptop.
- Search your lockfiles and build logs. Look for litellm==1.107.0 or version "1.107.0" in requirements*.txt, poetry.lock, uv.lock, Pipfile.lock and pdm.lock, and for "litellm-1.107.0" in CI logs from Oct 21, 2026. If litellm was unpinned or used a range like >=, any install between about 11:39 and 13:23 UTC (7:39 to 9:23 AM ET) that day could have pulled it. Other AI tools and agent frameworks list LiteLLM as a dependency, so check even if you never added it yourself.
- Check Docker images by tag and digest. You're exposed if you ran ghcr.io/berriai/litellm, litellm-database or litellm-non_root, or docker.io/litellm/litellm, at v1.107.0, or pulled latest, main-latest or main-stable on Oct 21 from about 11:48 UTC until BerriAI removed them (it confirmed removal at 14:32 UTC). Run docker images --digests | grep litellm and check what your Kubernetes pods or compose stacks actually pulled. Upwind lists the infected index digests as starting sha256:1bbcb1443bc9 (litellm and Docker Hub), sha256:c00f9d92c427 (litellm-database) and sha256:7b00e91cd2fe (litellm-non_root).
- Pin a clean image by digest, not tag. When we checked at about 12:30 PM ET on Oct 21, the floating tags and v1.107.0 were gone from both registries rather than repointed, so deploys that pull latest will fail. The v1.106.2 digests we saw, which match Upwind's clean list, are ghcr.io/berriai/litellm and docker.io/litellm/litellm sha256:7294b90f868c5c38c99b83021c7ba46f9b439e95f8e32964c925c7d2563a03f7, litellm-database sha256:35f2cec3a14bb297e08bfab56c1fc377432bc4071aaf71978fdff043a5d91e79, and litellm-non_root sha256:07fabea33dfc2b127e865c03112dfc76936334b29028ec05cdd355af2385dc04. For pip, pin litellm==1.106.2.
- Look for signs it ran. Per Upwind, /tmp/.pc_once_72129118c59f5636c0bb exists only after data was sent successfully; /tmp/remote_code_loader.lock, an environment variable PRIVCOLLECT_ACTIVE=1 or an orphaned python process with working directory / point to the loader. A missing marker proves nothing, since containers and tmp cleanup remove it. Check DNS and proxy logs for litellm.dev or www.litellm.dev, and block that domain.
- Clean up from the shell, then rebuild. Upwind's steps: delete cook.pth, cook.py, sitecustomize.py and any matching cook*.pyc and sitecustomize*.pyc from every affected site-packages, kill the detached python process holding /tmp/remote_code_loader.lock, then reinstall litellm 1.106.2. Rebuilding the environment or image from scratch is better.
- If 1.107.0 ever ran on a machine with internet access, assume the data left and rotate. Start with your AI coding tools: sign out of Claude Code, Cursor, Codex, GitHub Copilot and Gemini CLI on that machine, revoke their sessions or tokens from each vendor's account settings, and replace any Anthropic, OpenAI, Google or other API keys stored in their configs, environment or MCP settings. GitHub Copilot rides on your GitHub login, so revoke GitHub OAuth tokens and personal access tokens too.
- Then rotate cloud and infrastructure secrets: AWS, Azure and GCP keys and the instance or task role sessions on that host, Kubernetes and Vault tokens, CI secrets, SSH and GPG keys, npm and PyPI tokens, database passwords, and saved browser passwords and sessions. On a LiteLLM proxy, StepSecurity and Upwind say to rotate every provider key stored in the proxy database, the master and virtual keys, the salt key and the DATABASE_URL password. Upwind also suggests checking CloudTrail for GetCallerIdentity calls from the instance role around install time, then for use of that role from outside your infrastructure.
Related on VibeIncidents
- Aoki infostealer now steals Claude, Codex, Cursor and Gemini credentials, Symantec says
- Warden Stealer malware now targets local Cursor, Claude, Codex and MCP credentials, Gen Digital says
- Fake Apex Copilot coding agent on npm rerouted model traffic and dropped malware
Sources
- Upwind security research (LidorMachluf): litellm 1.107.0 compromised, BerriAI/litellm issue #47826 (Oct 21, 2026). Primary report
- BerriAI (ojensen-berri) in issue #47826: treating as SEV-0, PyPI quarantined 1.107.0 (Oct 21, 2026, 13:50 UTC)
- BerriAI in issue #47826: malicious Docker images removed, method not yet identified, pin 1.106.2 (Oct 21, 2026, 14:32 UTC)
- BerriAI in issue #47826: status update on three engineers' GitHub accounts and stolen GitHub CLI OAuth tokens (Oct 21, 2026, 16:32 UTC)
- Upwind in issue #47826: status update, PyPI clean, Docker tags still infected, attacker commit links (Oct 21, 2026, 13:23 UTC)
- StepSecurity: litellm 1.107.0 Compromised on PyPI: Backdoored Wheels Drop a Credential Stealer and an Hourly Remote Code Loader (Oct 21, 2026)
- AISLE: AISLE Found Compromised LiteLLM Package 3 Minutes After Release (Oct 21, 2026)
- Aikido: LiteLLM compromised again: infostealer and RAT found in version 1.107.0 (Oct 21, 2026)
- PyPI JSON API for litellm (latest release 1.106.2; 1.107.0 no longer listed)
- PyPI Blog: Incident Report: LiteLLM/Telnyx supply-chain attacks, with guidance (Apr 2, 2026)
Corrections and updates
Cite this entry
- Title
- LiteLLM 1.107.0 on PyPI and Docker shipped a credential stealer that also takes Claude Code, Cursor, Codex and Copilot logins
- Added
- Oct 21, 2026
- URL
- https://vibeincidents.com/incidents/litellm-1-107-0-pypi-docker-credential-stealer/
- Suggested citation
VibeIncidents. "LiteLLM 1.107.0 on PyPI and Docker shipped a credential stealer that also takes Claude Code, Cursor, Codex and Copilot logins." Oct 21, 2026. https://vibeincidents.com/incidents/litellm-1-107-0-pypi-docker-credential-stealer/