Dev.to Security 🔐 Cybersecurity 👁 0 📖 2 min read

The poisoned LiteLLM 1.107.0 problem, and the 30-second check I now run on every repo

On Oct 21, LiteLLM disclosed that v1.107.0 shipped compromised — malicious wheels on PyPI (live 11:39–13:23 UTC), poisoned Docker tags (v1.107.0, latest, main-latest, main-stable, 11:46–14:20 UTC), and GHCR images (until

On Oct 21, LiteLLM disclosed that v1.107.0 shipped compromised — malicious wheels on PyPI (live 11:39–13:23 UTC), poisoned Docker tags (v1.107.0, latest, main-latest, main-stable, 11:46–14:20 UTC), and GHCR images (until 13:51 UTC). The official announcement: https://docs.litellm.ai/blog/security-incident-oct-21-2026

The part that caught people off guard: in an affected environment, any Python start re-runs the implant. So the vendor's own response steps warn you not to start with pip install or pip show on a suspect box — you check files and metadata first, from the shell.

I turned the announcement's manual steps into a small checklist I now run on every repo and venv folder. Here's the method, then the tool that automates it.

The manual check (works from any shell, no Python startup)

  1. Version specs, evaluated not grepped. litellm==1.107.0 pinned = exposed. But litellm>=1.0, ~=1.107, ^1.107.0, or unpinned litellm in requirements/pyproject/Poetry files = admits the bad version — whether it actually installed it depends on whether you installed during the exposure windows above. A spec that excludes 1.107.0 = clean on this axis.
  2. Lockfiles. Check poetry.lock, uv.lock, Pipfile.lock for a resolved litellm 1.107.0 — the lockfile tells you what actually got installed, the manifest only tells you what was allowed.
  3. Dockerfiles and compose files. Tags v1.107.0 = exposed; latest / main-latest / untagged images pulled during Oct 21 11:46–14:20 UTC = suspect. Also compare against the compromised image digest published in the announcement.
  4. Installed environments — without starting Python. Read litellm-*.dist-info/METADATA directly in site-packages. If it says 1.107.0, treat the environment as compromised: rebuild from litellm==1.106.2, rotate every secret that box could reach, check CloudTrail.
  5. Implant markers. Look for cook.pth, cook.py, a planted sitecustomize.py, and /tmp/remote_code_loader.lock (the C2 daemon ran or is still running if that lockfile exists).

The automation

I packaged the above as litellm-check (13 rules, each mapped to a step in the official announcement), because I kept seeing "how do I know if I was exposed?" in issue threads:

pip install litellm-check
litellm-check scan ./your-project        # code side
litellm-check scan ~/.virtualenvs        # installed-env side

Output is a Markdown or JSON evidence report — file:line, the matched spec/tag, and the announcement basis for each finding. --fail-on critical works as a CI gate. Zero third-party dependencies, Python 3.11+, Apache-2.0.

The honest limit, printed on every report: a clean scan means "none of the known indicators were found" — nothing more. Environments rebuilt after exposure, images pulled without a definition file in the tree, or CI-only installs leave nothing on disk to find. This is evidence collection, not a safety certification.

If your stack exposes LiteLLM somewhere these 13 rules miss, rule PRs with fixtures are the most useful contribution.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.