TL;DR
A supply chain security investigation has identified malicious code in LiteLLM version 1.107.0, a Python package distributed through PyPI.
The affected package contains multiple files designed to execute code automatically when Python starts, retrieve attacker-controlled payloads, and maintain persistent access to compromised environments.
Based on the analyzed package, this should be treated as a malicious package compromise rather than simply suspicious package behavior.
UPDATE: Upwind Research First to Identify the LiteLLM Compromise
Upwind’s security research team was the first to identify the malicious litellm 1.107.0 release. We reported it to the maintainers in GitHub issue #47826 and were credited for the discovery. Our analysis found that all seven 1.107.0 wheels on PyPI are affected. The payload is not in the v1.107.0 git tag, which means it was injected into the build environment before the wheels were built. cook.py is a full credential stealer that sends encrypted data to www.litellm.dev, a lookalike domain unrelated to the official litellm.ai.
What happened?
Analysis of litellm 1.107.0 identified three particularly concerning files: cook.pth abuses Python’s .pth mechanism to execute: Python processes .pth files during interpreter startup, meaning the malicious module can execute without a user explicitly importing it. cook.py is then loaded through this mechanism and appears to form part of the malicious execution chain.
More significantly, the package contains sitecustomize.py, another file Python can automatically import during startup.
Together, these mechanisms give the malicious code an opportunity to execute whenever Python is launched in an affected environment.
Remote code execution and C2
The observed sitecustomize.py behavior goes considerably further than persistence. It retrieves infrastructure information from an attacker-controlled GitHub repository:
raw.githubusercontent.com/letters9813/pythonclient-test/main/domain.txt
The retrieved domain is then used to request additional Python code from:
http://{domain}/codepy
That response is dynamically compiled and executed.
This effectively gives the attacker remote code execution on affected systems, with the ability to change the payload delivered to compromised machines after the package has already been installed.
The package also contains an embedded payload encoded using Base64 and zlib that is decompressed and executed at runtime.
Persistence
The malicious code attempts to remain active in the background rather than simply executing once during installation.
Observed behavior includes:
- Daemonizing using fork() and setsid()
- Redirecting standard input/output to /dev/null
- Creating /tmp/remote_code_loader.lock
- Periodically contacting attacker-controlled infrastructure
- Fetching and executing updated Python code approximately every hour
This turns installation of the affected package into an ongoing compromise rather than a one-time malicious execution.
Why this is particularly dangerous
LiteLLM is used as an abstraction layer for interacting with multiple LLM providers and is commonly deployed in environments that have access to sensitive API credentials.
That makes compromise of the package particularly concerning.
Depending on how LiteLLM was deployed, an affected environment could potentially expose secrets such as LLM provider API keys, cloud credentials, application secrets, database credentials, or other environment variables accessible to the compromised process.
The presence of the backdoor does not by itself prove that every credential on an affected machine was stolen. However, organizations should assume credentials accessible to the compromised process may have been exposed until investigation establishes otherwise.
Indicators of compromise
Organizations investigating LiteLLM deployments should look for:
cook.pth
cook.py
sitecustomize.py
/tmp/remote_code_loader.lock
raw.githubusercontent.com/letters9813/pythonclient-test/main/domain.txt
http://{domain}/codepy GitHub account/repository: letters9813/pythonclient-test
Security teams should also review network telemetry for unexpected connections initiated by Python processes, particularly connections following retrieval of the domain.txt resource.
What should organizations do?
Organizations that installed litellm version 1.107.0 should treat affected systems as potentially compromised. First, identify installations:
pip show litellm | grep -E 'Name|Version'
Do not rely solely on uninstalling the package. Because arbitrary attacker-controlled code could have already executed, removing LiteLLM does not establish that the environment is clean.
Affected organizations should isolate and investigate systems where appropriate, remove malicious artifacts, review process and network activity, and rotate credentials and secrets accessible to the affected environment.
Particular attention should be given to credentials used by LiteLLM itself and secrets available through environment variables, mounted Kubernetes secrets, cloud workload identities, CI/CD credentials, and local configuration files.
Supply chain attacks don’t end at installation
This incident demonstrates why package security cannot rely exclusively on package names, maintainers, or vulnerability databases.
A legitimate and widely used dependency can become an execution path into downstream environments when malicious code enters the software distribution chain.
In this case, Python startup mechanisms such as .pth files and sitecustomize.py are especially powerful because they allow malicious code to execute without an application explicitly calling the malicious module.
For defenders, detecting the compromised dependency is only the beginning.
