跳到正文
DEV Community· Pesimmoq·· 3 小時前精選AI 評分80

LiteLLM 1.107.0 惡意版本排查與套件延遲安裝設定

LiteLLM 1.107.0 was malware. A 5-minute check for AI developers, and the one-line setting that would have skipped it

AI 導讀

LiteLLM 1.107.0 於 2026 年 10 月 21 日上載至 PyPI,惡意 wheel 會在每次 Python 啟動時執行並竊取 AI 工具憑證等資料;安全版本為 1.106.2。

推薦理由

這篇文章將 LiteLLM 事件轉化為可執行的排查清單,並示範用 uv 或 pip 延後安裝新版本及為緊急修補設例外。

正文 · 原文

On October 21, 2026, a malicious litellm==1.107.0 was published to PyPI. It is the second compromise of the package this year, separate from the one in March. PyPI has removed it. The safe version is 1.106.2.

LiteLLM is the library many agents and proxies use to call Claude, GPT and other models through one interface. It often arrives as a dependency you never installed on purpose. And this payload goes after AI coding tool credentials by name: Claude, Cursor, Copilot, Gemini CLI, Codex CLI and others.

The best technical analysis so far is the write-up by GMO Flatt Security (in Japanese). This post summarizes it for an English-speaking audience and adds the part I couldn't find elsewhere: how to make your installer refuse brand-new releases.

https://blog.flatt.tech/entry/litellm_2nd_compromise

What happened

Times are UTC, from Flatt Security's timeline and PyPI's release metadata.

Time Event
10-13 06:43 Attacker's GitHub account created
10-13 06:46 TLS certificate issued for the exfiltration domain litellm[.]dev
10-21 10:44 Legitimate 1.106.2 published
10-21 11:39 Malicious 1.107.0 published, about an hour later
10-21 PyPI removes 1.107.0

Three details matter.

  • The GitHub tag is clean. The malicious files exist only in the wheels on PyPI. Reading the source would not have caught it.
  • It runs every time Python starts, not just on import. The wheel drops a .pth file and a sitecustomize.py into site-packages. Python loads both automatically at startup, so any Python process in that environment triggers it, even one that never imports litellm.
  • It leaves a backdoor. A daemon fetches and executes remote code every hour, with the C2 domain read from a file on GitHub.

The legitimate 1.107.0rc1 and rc2 had been published days earlier, so 1.107.0 looked like the expected next release. Anyone who ran pip install -U litellm on October 21 is the most likely victim.

What it steals

Flatt Security lists 16 categories. The ones AI developers should care about most:

  • AI tool credentials: Claude, Cursor, Copilot, Gemini CLI, Codex CLI, Windsurf, Aider, OpenCode, Hugging Face tokens
  • Environment variables, including other processes' via /proc/*/environ. If you pass ANTHROPIC_API_KEY or OPENAI_API_KEY as env vars, assume they're gone
  • .env files and private key files
  • LiteLLM's own database, if you run the proxy: it queries the credentials table for your provider keys
  • SSH keys, AWS / GCP / Azure credentials, browser-saved passwords, shell history

On Claude Code specifically: per the official docs, credentials live in the macOS Keychain on macOS and in ~/.claude/.credentials.json on Linux and Windows. macOS also falls back to the file when the Keychain can't be written, for example over SSH. If you run Claude Code in CI or on a Linux box, treat that file as exposed.

The 5-minute check

I ran these on my own Mac. Nothing matched, but pip show alone would not have told me that.

1. Find every installed copy. pip show only checks the current environment. Search for the dist-info folder instead, which carries the version in its name and also catches copies inside uv tool and pipx environments.

find ~ -maxdepth 8 -type d -iname 'litellm-*.dist-info' 2>/dev/null

litellm-1.107.0.dist-info means that environment is infected.

2. Check lockfiles. A pinned 1.107.0 will reinfect whoever rebuilds the environment from an internal mirror or cache.

grep -rIl -i 'litellm' --include='requirements*.txt' --include='pyproject.toml' \
  --include='uv.lock' --include='poetry.lock' ~/code 2>/dev/null

3. Look for the markers.

ls -la /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock 2>&1
ps aux | grep -E 'cook|remote_code_loader' | grep -v grep

The first file means the data has already been sent. The lock file or a matching process means the backdoor is running. On macOS /tmp is cleared on reboot, so a missing marker is not proof of safety on its own. Combine it with step 1.

4. If you were hit, follow Flatt Security's removal steps, then rotate everything as if it was stolen. The AI-specific items people forget:

  • Revoke and reissue API keys in the Anthropic Console, OpenAI, Google AI Studio and any other provider
  • Claude Code: /logout, then /login. Do the same for Cursor, Codex and the rest
  • Every provider key stored in a LiteLLM proxy
  • Everything in your .env files
  • GitHub tokens, PyPI / npm tokens, SSH keys, cloud credentials

Also check each provider's usage page for traffic since October 21 that you don't recognize.

Don't install anything younger than 3 days

The malicious release was live for less than a day. Refusing releases that are only hours old would have skipped it entirely. Flatt Security's own registry proxy applies a 3-day quarantine, and its users were not affected. You can get the same effect with features already built into uv and pip.

uv: exclude-newer accepts a duration such as 24 hours, 1 week or 3 days, or an ISO 8601 duration such as P3D. It is compared against each file's upload time.

# pyproject.toml
[tool.uv]
exclude-newer = "3 days"

In a global ~/.config/uv/uv.toml, drop the [tool.uv] line and keep exclude-newer = "3 days".

pip: --uploaded-prior-to accepts a duration in days in the P3D form. It only works with indexes that expose upload times, which PyPI does.

pip install --uploaded-prior-to P3D litellm

# or make it the default
export PIP_UPLOADED_PRIOR_TO=P3D

If your pip doesn't recognize the option, upgrade pip.

The catch is urgent fixes. When a library ships a same-day security fix, you can't wait three days. uv lets you exempt single packages with exclude-newer-package:

[tool.uv]
exclude-newer = "3 days"
exclude-newer-package = { cryptography = false }

With pip, unset the variable for that one install. "Wait by default, opt out on purpose" leaves a trace in your shell history or commit when you skip the delay.

For Node.js, pnpm has a setting for the same purpose, minimumReleaseAge (https://pnpm.io/settings).

Summary

  • litellm==1.107.0 is malware. Use 1.106.2. The GitHub source was clean; only the PyPI wheels were poisoned.
  • It runs on every Python startup and targets AI tool credentials, environment variables, .env files and the LiteLLM proxy database.
  • Check for installed copies with find, not just pip show. Check lockfiles and the marker files.
  • If you were hit, rotate every key, including your model provider API keys.
  • Set exclude-newer = "3 days" in uv or PIP_UPLOADED_PRIOR_TO=P3D for pip, and exempt urgent fixes explicitly.

If you run Claude agents on Claude Managed Agents, vault credentials of type environment_variable sit in the sandbox only as opaque placeholders and are swapped for the real secret at egress, so a poisoned dependency that dumps environment variables gets the placeholder, not the key: https://platform.claude.com/docs/en/managed-agents/vaults

I write about Claude API changes as they ship. The English edition of my Claude 5 migration guide is on Gumroad: https://persimmoq.gumroad.com/l/claude-5-migration-guide

來源:DEV Community · dev.to