LiteLLM 1.107.0 was published to PyPI and to GitHub Container Registry on October 21, 2026 with a credential stealer inside it. If you installed that exact version, or pulled ghcr.io/berriai/litellm by a floating tag in the middle of the day, treat every secret that environment could read as exposed. Roll back to 1.106.2, rebuild rather than patch in place, and rotate from a clean machine.
This is a LiteLLM supply-chain compromise worth a coding-agent audience's attention for one reason: the stealer goes after the login files of the AI tools themselves. The two primary write-ups, from Socket and Wiz, list Claude Code, Codex, Gemini CLI and Cursor credential files among its targets.
Quick answers
| Question | Answer |
|---|---|
| Am I affected? | Only if you installed litellm==1.107.0 from PyPI or ran the v1.107.0 image (or latest, main-latest, main-stable pulled on October 21). |
| Is there a fix? | Pin to 1.106.2, the most recent safe version per Wiz (Socket does not certify earlier releases). Rebuild environments; uninstalling is not enough. |
| What was stolen? | Cloud keys, SSH/GPG/TLS keys, .env files, browser data, AI tool login files, and the proxy's provider-key table when DATABASE_URL is set. |
Does it need import litellm? | No. It runs from Python startup hooks, so any Python process in the environment can trigger it. |
| Does data leave my machine? | Yes, in the affected case: encrypted and POSTed to www.litellm[.]dev/healthcheck. |
What happened, and when
Socket reports that 1.107.0 reached PyPI at 11:39:51 UTC and that its AI scanner flagged the wheels about seven minutes later. The container build ran earlier, from 10:51 to 11:06 UTC. Wiz's timeline has the attacker pushing ten commits to a lookalike repository named Berri-AI/litellm (note the extra hyphen) between 08:56 and 10:46 UTC, the PyPI upload at 11:39, and the malicious Docker tags being removed around 13:53 UTC. Wiz says the PyPI release was quarantined in the early afternoon.
The affected artifacts, per Socket and Wiz:
- PyPI: all seven
litellm-1.107.0wheels (macOS x86-64 and arm64, manylinux and musllinux for x86-64 and aarch64, Windows amd64). - Containers:
ghcr.io/berriai/litellm:v1.107.0, confirmed by Socket. Wiz and Upwind also listlitellm-database,litellm-non_rootanddocker.io/litellm/litellm, which Socket did not extract itself.
This is not the first time LiteLLM has appeared in our coverage: we covered the earlier credential-reseller economy in AI API key theft: inside the criminal reseller supply chain, where stolen provider keys are loot, compute and cover. A compromised gateway that stores every provider key a team uses is a shortcut to exactly that market.
LiteLLM is a gateway and SDK that routes calls to many model providers, and the proxy often holds every provider key a team uses. Beam's CVE database tracks it on the LiteLLM tool page.
How the attacker got a release out
Wiz reports that BerriAI told it the malicious actions were performed through three engineers' GitHub accounts, apparently with stolen GitHub CLI OAuth tokens. One account triggered the release run and another approved it. BerriAI says all tokens involved were revoked.
Socket's provenance analysis adds detail. The Linux amd64 image's provenance shows the release workflow (BerriAI/project-releaser, run 39587059944) was dispatched with source_owner set to Berri-AI, the lookalike, instead of BerriAI. The recorded source revision contained the payload files, byte-for-byte identical to the ones in the PyPI wheel.
Two commit details matter for anyone reviewing their own release pipelines:
- A commit at 09:48 UTC added
data = "cook"to the Maturin configuration, which packaged the payload directory into the wheel. The tagged release'spyproject.tomldoes not carry that setting, so reviewing the tag alone would have missed it. - A later commit added
COPY cook ./cookto the Dockerfiles. Wiz notes the first nine commits were made on GitHub.com under a Proton address with GitHub's verified signature, so a "Verified" badge did not mean the author was a maintainer.
Socket is explicit about what it could not establish: how the source_owner override was authorized, whether the same workflow published the wheels, and what the job logs show. Those remain open.
The mechanism: Python startup hooks
The wheels install three files outside the litellm/ package directory, directly into the site-packages root:
cook.pth: a one-line import that Python'ssitemachinery executes on every start.cook.py: the stealer, internally calledprivcollect.sitecustomize.py: a remote loader.
Because .pth files and sitecustomize run at interpreter startup, the payload does not depend on LiteLLM ever being imported. Running pip in the environment can re-trigger it. Wiz says combining .pth and sitecustomize.py appears to be the first documented case in the wild, and assesses the code as likely LLM-assisted (a dead exec_py module, generic try/except blocks). That is Wiz's judgment, not a confirmed fact.
What the stealer collects
Socket counts 16 collection modules, each with its own error handler:
- Cloud and deployment: AWS, Azure, Google Cloud, Kubernetes, Docker, GitHub CLI, Vault, Terraform, Packer, CI configuration, and container-mounted secrets.
- Developer accounts: Git credentials, npm and PyPI configuration,
.netrc,.envfiles, SSH keys, GPG and TLS private keys. - AI tooling:
~/.codex/auth.json,~/.claude/.credentials.json,~/.gemini/oauth_creds.json,~/.cursor/mcp.json, plus configuration for Copilot, Windsurf, Kiro, Zed, Continue, OpenCode and Hugging Face. - Browsers and workstation: Chromium and Firefox login, cookie and history databases, shell histories, host and network details.
- Runtime credentials: non-empty environment variables, other readable processes' environments on Linux, AWS instance and task credentials, Google Cloud service-account tokens and Azure instance metadata.
- LiteLLM itself: when
DATABASE_URLis set, a Prisma child process queries the proxy's credentials and model-configuration tables (up to 500 rows each). Wiz quotes the query againstLiteLLM_CredentialsTable. Socket's analysis does not show that any stored credential was successfully decrypted.
Platform limits exist: Socket notes the Linux /proc inspection fails on typical macOS hosts and the Chromium password routine does not recover plaintext passwords there, though it still copies the browser databases. The AI-tool file theft and environment collection still apply.
Exfiltration and the second stage
Results are encrypted with a random AES-256-CBC key wrapped with an embedded RSA-4096 public key, packed as a gzip tar and POSTed to http://www.litellm[.]dev/healthcheck. The endpoint name is misleading: the body is the stolen data. Socket reports up to four attempts with a 120-second timeout each. After an HTTP 200, the collector writes /tmp/.pc_once_72129118c59f5636c0bb so it does not collect again. An absent marker does not prove a host was clean, because failed uploads or replaced containers leave none.
sitecustomize.py is a separate loader. It takes a lock at /tmp/remote_code_loader.lock, forks a detached process, and repeatedly fetches domain.txt from a GitHub repository (letters9813/pythonclient-test). If a domain resolves, it downloads Python from http://<domain>/codepy and runs it with exec, with no signature check. At Socket's observation time the pointer file was empty; historical values were placeholders such as localhost:18909. Both firms say no active second stage was observed, but the pointer is mutable, so that can change. Wiz says GitHub took the dead-drop repository down.
What this means if you run AI coding agents
LiteLLM often sits behind coding agents as the gateway that holds provider keys, and it is installed on the same laptops and CI runners where Claude Code or Codex run. Work through these steps in order.
- Find out whether you pulled it. Check lockfiles, build logs and caches for
litellm==1.107.0. Locally,pip show litellmprints the installed version, andpip cache list litellmshows cached wheels. For containers, compare running image digests against the digests in Socket's report (image indexsha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e) rather than trusting tags. - Look for the payload files without running Python. Search
site-packagesforcook.pth,cook.pyandsitecustomize.py. Socket cautions thatsitecustomize.pycan be legitimate, so compare hashes with the IOC list in its post. Also look for/tmp/.pc_once_72129118c59f5636c0bb,/tmp/remote_code_loader.lockandPRIVCOLLECT_ACTIVE=1in process environments. Inspect with trusted tooling: running the environment's own Python or pip can re-trigger the hook. - Isolate before you clean. If the payload files are present, isolate the host or container and preserve process, filesystem and network evidence first.
- Rebuild, don't repair. Remove the environment, pin
litellm==1.106.2(the most recent safe version per Wiz) and rebuild from a reviewed artifact. Pin image digests, not floating tags. - Rotate from a clean machine. Cloud sessions and keys, provider API keys, every key stored in the LiteLLM proxy database, SSH and GPG keys, registry tokens, and database credentials. For coding agents, sign out and back in so the stored Claude Code, Codex and Gemini tokens are reissued, and review
~/.cursor/mcp.jsonfor any secrets pasted into MCP server entries. - Hunt in logs. Search egress for POSTs to
litellm[.]dev/healthcheck, requests toraw.githubusercontent.com/letters9813/..., and any/codepyfetches. Review cloud, identity and registry audit logs for use of the exposed credentials. Socket suggests scoping GitHub blocks to that path, not the whole shared domain. - Fix your own release path. Maintainers should audit who can dispatch release workflows, restrict builds to approved repository identities and reviewed commits, and keep publishing credentials separate from dependency installation and tests.
If you run LiteLLM only as a pinned dependency inside a lockfile with hashes, you are likely fine: the compromised version is a specific release. Unpinned pip install litellm in a Dockerfile or CI job between publication and quarantine is the exposure to look for.
The wider lesson is one we keep returning to in npm supply-chain worms hitting AI tooling and in the AI agent application and supply-chain security guide: a developer machine that runs agents holds many long-lived, readable secrets, and a single poisoned dependency reads them all. Plaintext files like ~/.codex/auth.json are convenient for the tools and equally convenient for a stealer. See also how a fake Claude Code installer harvested credentials and MCP security in practice for the configuration side, and AI agent deployment and incident response for a rotation plan.
What Beam can and cannot do here
Beam does not scan Python packages or container images, and it would not have flagged litellm==1.107.0. beam scan checks local skill and instruction files and MCP configurations for risky patterns, and with --mcp it examines version pinning. The docs say plainly that a pinned version improves reproducibility but does not prove that package safe, and the scan does not launch the server or inspect live behavior.
What Beam does give you is visibility into agent sessions on your own machine: it flags risky agent actions such as credential exposure, and keeps its data on-device. That helps you reason about which secrets an agent session touched, which feeds your rotation list. It is heuristic, hook-based for Claude Code and Codex, and not a sandbox: it does not stop a Python startup hook from reading files. Use package pinning with hashes, a registry cooldown or allowlist, and egress controls for that layer.
Caveats
Socket's findings rest on static analysis of the wheel and the provenance documents, and it did not extract every image. Wiz's remediation guidance in its post is brief; the checks above combine its notes with Socket's more detailed list. The release workflow's authorization and the exact set of compromised credentials were not fully resolved at publication.
Frequently asked questions
Which LiteLLM versions are malicious?
Only litellm 1.107.0 is reported malicious: all seven PyPI wheels and the ghcr.io/berriai/litellm:v1.107.0 image, which also resolved for latest, main-latest and main-stable around 13:14 UTC on October 21, 2026. Wiz names 1.106.2 as the most recent safe version (Upwind, cited by Socket, also recommends it); Socket names no fixed release and says it did not certify every earlier artifact.
Does uninstalling LiteLLM remove the malware?
No. The wheel drops cook.pth, cook.py and sitecustomize.py into the site-packages root, outside the litellm package directory, and Python runs them at every interpreter start. Socket notes that uninstalling does not remove those files or stop a running loader. Rebuild the environment instead.
What did the stealer target?
Cloud and deployment credentials (AWS, Azure, Google Cloud, Kubernetes, Vault, Terraform), SSH, GPG and TLS keys, .env files, browser databases, and AI tool files such as ~/.claude/.credentials.json, ~/.codex/auth.json, ~/.gemini/oauth_creds.json and ~/.cursor/mcp.json. With DATABASE_URL set, it also queried the LiteLLM proxy credentials table.
How did the attacker publish the release?
BerriAI told Wiz the malicious actions were taken through three engineers' GitHub accounts, apparently using stolen GitHub CLI OAuth tokens, with one account triggering the release run and another approving it. Socket could not confirm how the workflow was authorized, so the exact chain is partly unresolved.
Does Beam detect this?
Not directly. Beam watches coding-agent actions and scans skill and MCP files, not PyPI packages or container images. It can show when an agent reads or exposes credential files in a session, but it is not a package scanner or a sandbox for Python startup hooks.
Related reading
- AI API key theft: inside the criminal reseller supply chain
- npm supply-chain worms and AI tooling
- AI agent application and supply-chain security
- Fake Claude Code installers and InstallFix
- How Beam watches agents locally
Details are accurate as of October 21, 2026, while both vendors were still updating their analyses. Check the linked Socket and Wiz posts for new indicators.

