deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Malicious LiteLLM 1.107.0 on PyPI targeted AI coding credentials in second 2026 compromise

A malicious litellm 1.107.0 release was live on PyPI for under a day and harvested AI coding tool credentials; the safe version is 1.106.2 and a three-day install delay would have blocked the bad one.

Malicious LiteLLM 1.107.0 on PyPI targeted AI coding credentials in second 2026 compromise

On October 21, 2026, a malicious release of the widely used litellm Python package landed on PyPI and stayed downloadable for less than a day before being pulled. According to a dev.to write-up summarizing an analysis by GMO Flatt Security, version 1.107.0 carried data-stealing malware. It was the second compromise of the package in 2026 and is unrelated to an earlier incident in March. Version 1.106.2, published the same morning, is regarded as safe.

How the attack was staged

The dev.to post reconstructs the timeline from Flatt Security's findings and PyPI release metadata. The attacker's GitHub account was created on October 13 at 06:43 UTC, and a TLS certificate for the exfiltration domain litellm[.]dev was issued three minutes later. On October 21, the legitimate 1.106.2 appeared at 10:44 UTC; the poisoned 1.107.0 followed at 11:39 UTC, roughly an hour afterward, and PyPI removed it later that day.

Two details made the release convincing. The 1.107.0 tag in the project's GitHub repository contained no malicious code — the payload existed only in the wheels uploaded to PyPI — so auditing the source would not have helped. And because 1.107.0rc1 and rc2 had shipped normally a few days earlier, a final 1.107.0 was precisely what someone upgrading that day would expect to receive.

What the payload did

According to the write-up, the malware did not wait for the package to be imported. The wheel planted a .pth file and a sitecustomize.py in site-packages, and Python loads both on every startup, so any Python process in the compromised environment set it off. Alongside the credential theft, the payload ran a daemon that downloaded and executed remote code on an hourly schedule, with its command server's address read from a file hosted on GitHub.

What was stolen

Flatt Security catalogued 16 categories of harvested data. The list names credentials for AI coding tools specifically: Claude, Cursor, Copilot, Gemini CLI, Codex CLI, Windsurf, Aider, OpenCode and Hugging Face tokens. Environment variables were collected not just from the malware's own process but from other processes via /proc/*/environ, so the post advises treating anything passed as ANTHROPIC_API_KEY or OPENAI_API_KEY as lost. .env files, private keys, SSH keys, cloud credentials, browser passwords and shell history were also collected, and where the LiteLLM proxy was running, the malware queried its database for stored provider keys.

The post adds a caveat for Claude Code users: credentials live in the macOS Keychain, but Linux and Windows rely on ~/.claude/.credentials.json, and macOS falls back to that file when the Keychain is not writable, such as over SSH — anyone running Claude Code in CI or on servers should assume that file was read.

How to check for it

Because pip show only inspects the active environment, the author recommends searching the home directory for litellm-*.dist-info folders, which also catches copies tucked inside uv tool and pipx environments; a folder named litellm-1.107.0.dist-info indicates infection. Lockfiles pinning 1.107.0 matter too, since a rebuild from an internal mirror or cache would reinstall the bad wheel. Artifacts left behind include /tmp/.pc_once_72129118c59f5636c0bb — a sign data was already sent — and /tmp/remote_code_loader.lock or a matching process, which indicates the backdoor is active. Since macOS clears /tmp on reboot, absence of these files alone proves little.

Anyone affected should follow Flatt Security's cleanup steps and rotate every secret: provider API keys, Claude Code and other tool logins, keys held in a LiteLLM proxy, .env contents, registry and GitHub tokens, SSH keys and cloud credentials, plus a review of provider usage pages for unrecognized activity since October 21.

The setting that would have skipped it

The malicious release existed for under a day, meaning an installer that ignored anything only a few hours old would never have fetched it. Flatt Security's own registry proxy enforces a three-day quarantine, and its users were unaffected. The same behavior is available directly in uv and pip: uv accepts exclude-newer = "3 days" under [tool.uv], with exclude-newer-package to exempt packages that genuinely need same-day security patches, while pip supports --uploaded-prior-to P3D or the PIP_UPLOADED_PRIOR_TO environment variable, working on indexes that report upload times, which PyPI does. On the Node side, pnpm offers an equivalent minimumReleaseAge setting. The trade-off is that urgent fixes are delayed too, so overriding it should be a deliberate, visible act.

Why it matters

LiteLLM sits inside many AI stacks, often as a transitive dependency of agents and proxies, so developers can be running it without ever having installed it deliberately. The incident shows attackers timing a release to blend into a normal publishing cadence, shipping clean source alongside poisoned wheels, and aiming squarely at AI developer credentials. The defenses are cheap: search for the dist-info folder rather than trusting pip show, stay on 1.106.2, and consider a short install delay that would have turned this attack into a non-event.

  • #python
  • #security
  • #supply-chain
  • #pypi
  • #llm

Related posts