{"slug": "litellm-1-107-0-shipped-a-credential-stealer-what-to-check-and-what-to-rotate", "title": "LiteLLM 1.107.0 shipped a credential stealer: what to check and what to rotate", "summary": "BerriAI's LiteLLM 1.107.0 was published to PyPI and Docker registries on 2026-10-21 carrying a credential stealer in all seven compiled wheels and in the v1.107.0 container images, according to the company's incident report and StepSecurity's analysis. The malicious artifacts were built from a lookalike repository, Berri-AI/litellm, after an attacker used GitHub CLI credentials from three developer accounts and an organization owner token to disable branch protection; the release was removed from PyPI by 13:23 UTC and affected Docker tags were cleaned up by 14:20 UTC. The malware installs cook.pth, cook.py and sitecustomize.py into site-packages so it runs on every Python interpreter start, harvesting browser data, SSH and GPG keys, cloud and CI credentials, .env files and AI coding tool tokens, and exfiltrating them via HTTP POST to litellm.dev.", "body_md": "# LiteLLM 1.107.0 shipped a credential stealer: what to check and what to rotate\n\nA malicious litellm 1.107.0 was published to PyPI and Docker registries on 2026-10-21. A practical checklist: how to tell if you are affected, how to clean up, and which secrets to rotate.\n\nOn 2026-10-21, `litellm==1.107.0` was published to PyPI with a credential stealer inside every one\nof its compiled wheels. Container images tagged `v1.107.0` were affected too. If you run LiteLLM anywhere, this is a checklist.\n\n**Updated 2026-10-22** with BerriAI’s [incident report](https://docs.litellm.ai/blog/security-incident-oct-21-2026)\n(its 20:30 UTC update): exact times, how the release got out, more files to look for and more secrets to\nrotate. The investigation is still open, so check the report for later updates before acting.\n\n## What happened\n\nTimes are UTC, 2026-10-21, from BerriAI’s incident report and\n[StepSecurity](https://www.stepsecurity.io/blog/litellm-1-107-0-compromised-pypi-backdoored-wheels-credential-stealer):\n\n| Time | Event | \n|---|---|\n| 08:56–10:46 | Payload commits pushed to a lookalike repository, `Berri-AI/litellm` (the real one is`BerriAI/litellm` ) | \n| 10:08 | Branch protection blocks a change to the private release workflow; a privileged developer credential overrides it | \n| 10:46 | The modified workflow builds from the lookalike repository | \n| 11:11 | A second developer account approves the production release | \n| 11:39 | Seven `litellm==1.107.0` wheels uploaded to PyPI | \n| 11:46 | Infected images published; `latest` ,`main-latest` and`main-stable` point to them | \n| 11:53 | A third developer account deletes the workflow run records | \n| 12:06 | Compromise reported in BerriAI/litellm issue #47826 | \n| by 13:23 | `1.107.0` removed from PyPI | \n| 13:51 | Affected GHCR tags no longer available | \n| 14:20 | All affected Docker Hub tags removed or pointed back to clean images | \n\n### How it got out\n\nAccording to BerriAI, the attacker held GitHub CLI credentials of three developer accounts: one\nchanged and ran the release workflow, one approved the production release, and one deleted the\nrun records. A token of a GitHub organization owner was used to turn off branch protection. The\nofficial `v1.107.0` source tag does not contain the malicious files; the artifacts were built from\nthe lookalike repository. How the attacker got the tokens in the first place is not yet confirmed.\n\n### What is affected\n\n- **PyPI:**`litellm==1.107.0` , all seven wheels (macOS, Linux glibc and musl, Windows). The sdist\nhas a tampered build config but no payload.\n- **Docker:** the`v1.107.0` tag of`ghcr.io/berriai/litellm` ,`litellm-database` ,`litellm-non_root` and`docker.io/litellm/litellm` . The floating tags`latest` ,`main-latest` and`main-stable` pointed to the infected image from 11:46 to 14:20 UTC, about two and a half hours.\nThe Docker Hub index digest is`sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e` .\n- **Reported clean:** BerriAI says every earlier version is safe; StepSecurity also checked`1.107.0rc1` ,`1.107.0rc2` and the`1.103.x` –`1.106.x` releases.\n\n### What the malware does\n\nIt installs three files into `site-packages`: `cook.pth`, `cook.py` and `sitecustomize.py`.\n`cook.pth` imports `cook`, so the stealer runs on **every Python interpreter start** in that\nenvironment. Your code does not have to import `litellm`.\n\nIt collects browser data, SSH and GPG keys, cloud and CI credentials, `.env` files, the environment\nvariables of readable processes and tokens of AI coding tools. If `DATABASE_URL` is set, it also\ndumps the LiteLLM proxy database, which holds upstream provider API keys. The bundle is encrypted\nand sent by HTTP POST to `litellm.dev`. On Linux and macOS a second component polls a dead-drop\nfile every hour and executes whatever code it points to.\n\n## Are you affected?\n\n**Do not run Python in an environment you suspect.** Every interpreter start re-runs the stealer,\nso `pip show litellm` is not a safe check. Use file-system and lockfile searches instead:\n\n```\n# Is the malicious version pinned anywhere in your repos?\ngrep -rn \"litellm.*1\\.107\\.0\" --include=\"requirements*.txt\" --include=\"*.lock\" --include=\"pyproject.toml\" .\n\n# Are the payload files on this host or in an extracted image layer?\nfind / \\( -name cook.pth -o -name cook.py -o -name 'cook*.pyc' -o -name 'sitecustomize*.pyc' \\\n  -o -name \"litellm-1.107.0*\" \\) 2>/dev/null\n\n# Loader still running? (a live holder process means yes)\nls -l /tmp/remote_code_loader.lock /tmp/.pc_once_* 2>/dev/null\n```\n\nFinding any of these confirms exposure; not finding them does not prove a host is clean. A\n`/tmp/.pc_once_*` file is written only after the stealer got a successful reply from its server, so\nit means the data left. `sitecustomize.py` on its own is not proof: some environments ship one.\n\nFor containers, check which tags and digests you pulled, not what runs inside:\n\n```\ndocker images --digests | grep -i litellm\n# compromised Docker Hub index: sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e\n```\n\nTreat as compromised:\n\n- any host or CI runner that installed `litellm==1.107.0` , even briefly;\n- any container started from a `v1.107.0` image, or from`latest` ,`main-latest` or`main-stable` pulled between 11:46 and 14:20 UTC on 2026-10-21;\n- any machine where a `pip install litellm` without a pin ran on 2026-10-21 between 11:39 UTC and\nthe PyPI removal.\n\nNetwork indicators: requests to `litellm.dev` or `www.litellm.dev`. A request to the path `/codepy`\nmeans the second stage actually ran.\n\nMarker file hashes (Linux and macOS, SHA-256), for matching:\n\n```\ncook.pth          7f191632e7320705d154b85204f1ae546b543acbd7e8861229b76f5042b92bdb\ncook.py           9dd0a3926f96a37eb86cf1ee2310d9be93139cc4ebef3ef9e2efe9531390be25\nsitecustomize.py  34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa\n```\n\n## What to do\n\n1. **Isolate.** Kill any process holding`/tmp/remote_code_loader.lock` . Block`litellm.dev` at DNS\nor egress.\n2. **Rebuild, don’t clean.** Rebuild containers from a clean image. For hosts, reinstall the\nenvironment rather than deleting three files and moving on.\n3. **Pin.**`litellm==1.106.2` , or the`v1.106.2` image by digest. Purge cached`1.107.0` wheels\nand images from your mirrors and registries.\n4. **Rotate everything the host could reach.** Assume the secrets were taken: the stealer output is\nencrypted, so you cannot confirm from the network side that nothing left.\n  - the instance or task role of the host, cloud keys, SSH and GPG keys, registry and CI tokens, Kubernetes and Vault tokens, and any secret in the environment of any process on the host;\n  - tokens of AI coding tools on developer machines;\n  - on a proxy with a database: every provider API key stored in it and in the model configs,\nthe master key, the salt key, the virtual keys and the `DATABASE_URL` password.\n5. **Look back.** Search network logs for`litellm.dev` and`/codepy` . On AWS, look in CloudTrail\nfor`GetCallerIdentity` from the instance role around the install time, then for that role’s\ncredentials used from outside your infrastructure. Audit provider-side usage for keys that were\non affected hosts.\n\n## Lessons that apply to any gateway\n\nAn LLM gateway holds the keys to all your model vendors, so it is a high-value target. A few habits reduce the blast radius, whichever gateway you run:\n\n- **Pin versions and digests.** Never deploy`latest` . Update on purpose, after a delay.\n- **Install from a lockfile with hashes** (`pip install --require-hashes` , or your language’s\nequivalent).\n- **Restrict egress** from the gateway. A proxy that only needs to reach model vendors has no\nreason to reach arbitrary hosts.\n- **Keep vendor keys out of plaintext** in env vars and databases where you can.\n- **Verify signatures and provenance** of what you pull, when the project publishes them.\n\nThis is the second incident of this kind for LiteLLM this year; in March 2026 versions 1.82.7 and 1.82.8 were compromised. No ecosystem is immune: dependencies can be poisoned in any language.", "url": "https://wpnews.pro/news/litellm-1-107-0-shipped-a-credential-stealer-what-to-check-and-what-to-rotate", "canonical_source": "https://blog.ai-process.dev/2026/10/21/litellm-1-107-0-credential-stealer/", "published_at": "2026-10-21 19:08:00+00:00", "updated_at": "2026-11-04 18:51:10.109554+00:00", "lang": "en", "topics": ["ai-safety", "ai-infrastructure", "ai-tools", "developer-tools"], "entities": ["LiteLLM", "BerriAI", "StepSecurity", "PyPI", "Docker Hub", "GitHub", "litellm.dev", "Berri-AI/litellm"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/litellm-1-107-0-shipped-a-credential-stealer-what-to-check-and-what-to-rotate", "markdown": "https://wpnews.pro/news/litellm-1-107-0-shipped-a-credential-stealer-what-to-check-and-what-to-rotate.md", "text": "https://wpnews.pro/news/litellm-1-107-0-shipped-a-credential-stealer-what-to-check-and-what-to-rotate.txt", "jsonld": "https://wpnews.pro/news/litellm-1-107-0-shipped-a-credential-stealer-what-to-check-and-what-to-rotate.jsonld"}}