Compromised LiteLLM 1.107.0 on PyPI shipped a credential stealer and backdoor

Translated by a model; the original is in Russian.

· Security
Version 1.107.0 of the popular LLM gateway LiteLLM, uploaded to PyPI, carried a credential stealer and a remote-code-execution backdoor. The GitHub source was clean, yet the malicious files ran on every Python process start on the host.

cover.svg

SafeDep researchers report that the LiteLLM 1.107.0 release on PyPI was compromised: all seven wheels (Linux, macOS, Windows) dropped three extra files into site-packages — a credential stealer and a backdoor. The upstream BerriAI/litellm source on GitHub contained none of them. PyPI has since pulled the release.

Neighbouring versions 1.106.2 and the 1.107.0rc1/rc2 candidates are clean, as are the companion packages litellm-proxy-extras and litellm-enterprise that the release pinned.

What the malware did

A file named cook.pth held the line import cook, so Python ran cook.py — the stealer — on every startup. It scooped up SSH keys, cloud credentials, CI/CD secrets, AI-tool tokens, browser passwords and the LLM-provider keys from a LiteLLM proxy database. Notably, its ai_devtools module targeted tokens for Claude Code, Cursor, Copilot, Gemini CLI and a dozen more assistants, while env_vars read other processes' environments through /proc/<pid>/environ.

The data was encrypted with an AES-256 key, the key itself wrapped with RSA, and POSTed to www.litellm[.]dev (not the project's own domain). The second file, sitecustomize.py, launched a background daemon: once an hour it read a server address from a GitHub file, ran the stealer again, and downloaded arbitrary code from that server to run via exec().

Because both files fired on the start of any Python process — the app, pip, IDE language servers, CI jobs — even a process that never imported LiteLLM got infected.

How the implant got in

The sdist's pyproject.toml had a single extra line — data = "cook" in the maturin section — which copied a cook/ folder into the wheel. The attacker also rolled the version number back from 1.108.0 to 1.107.0 and pinned the companion packages to the rc2 values, so a dependency diff against rc2 showed nothing unusual.

The built wheels match the output of BerriAI's normal release pipeline: the same maturin version, correct RECORD entries, separate native builds for all three platforms. In the Windows wheel every .py file has CRLF line endings — the fingerprint of a Windows checkout. SafeDep assesses, with moderate-to-high confidence, that BerriAI's private pipeline built the wheels from an attacker-modified source; only the pipeline's own logs can confirm the cause.

The aftermath

About two hours after publication, the letters9813 account that held the command-server address returned 404, and the backdoor could no longer find a server. But hosts that had already started the daemon could have fetched and run second-stage code. Affected users should check for the named files and /tmp indicators and rotate every secret the Python process could reach.


Source: Hacker News

Comments

Sign in, to comment.

  • No comments yet.