Introduction: The Illusion of Security in an Innocent Command
Who doesn’t know the pip command? It’s one of the most used commands for anyone developing in Python or regularly using open-source software distributed on the PyPi repository. pip is that command that (at least in my experience) never disappoints and is practically essential (though it’s recently been giving way to other tools like Poetry and uv) for anyone needing to install libraries for Python development. But sometimes, this sense of security can lead us into a nasty trap.
But what happens when this trust is betrayed? That’s exactly what happened on March 24, 2026.
A carefully laid trap by a hacker group known as TeamPCP turned pip install into a weapon to harvest secrets (like system variables, SSH keys, cloud provider credentials) and attempt lateral movement through Kubernetes clusters.
Anatomy of a Foretold Disaster: What Happened to LiteLLM?
The injected payload was no joke: it was a credential stealer designed to scour the environment for env vars, SSH keys, AWS/GCP/Azure credentials, and Kubernetes tokens, then exfiltrate everything to a malicious domain (models.litellm.cloud).
The team behind LiteLLM has CI/CD workflows to take their software from source code to a package on the PyPi repo. One of these workflows is responsible for scanning their code and dependencies (using Trivy) before distributing the package.
And it was precisely Trivy (apparently) that allowed the TeamPCP group to bypass this security workflow to upload the two vulnerable versions of LiteLLM to PyPi.
The Betrayal of pip install <package>
As I wrote above, the pip command is that one command you usually have blind faith in, entrusting it with the task of updating or installing the various necessary libraries. By using it, however, we hand over “control” to it.
Leaving control to pip, at least in this case, led to the entry of vulnerable LiteLLM versions into thousands of systems, which became insecure and potentially compromised. This happened simply because the decision was made to update libraries without caring which version was being installed.
And this isn’t just theory. The LiteLLM team confirmed that those who used their official Docker image were not affected. Why? Simple: that image used a requirements.txt file with pinned versions! It’s concrete proof that this practice, on its own, acted as a shield for who knows how many companies.
Example of an Insecure Dockerfile
# VULNERABLE Dockerfile
FROM python:3.11-slim
WORKDIR /app
RUN pip install litellm fastapi uvicorn
...
A build based on a Dockerfile like this, executed during the attack’s time window, would have installed version 1.82.7 without batting an eye, opening a huge security hole in the infrastructure.
The Unexpected Hero: requirements.txt and the Power of Pinning
With pinning, we’re telling pip, “install this version and never, ever update it.” In practice, we’re virtually fixing a specific version with a thumbtack. This is not just a best practice (in Python, as well as in Docker or other package management software) to avoid breaking changes introduced in new packages, but it also prevents the reckless installation of new versions with potential problems.
One of those problems it prevents, in fact, (though in a relative sense) is the installation of new, untested versions that are potentially affected by major bugs or vulnerabilities.
Leveling Up: From a Quick Fix to a Supply-Chain Security Strategy
Supply-chain security is one of the most critical challenges for modern companies that distribute software. Part of the challenge is that there is no single, functional definition of supply-chain security, and it’s a challenge that spans an extremely broad area, including everything from physical threats to cyber threats (as in this case).
If we take, for example, a piece of software like LiteLLM, whose requirements.txt file contains about 80 lines of dependencies, and if we consider that each dependency will likely use other dependencies, it creates a chain of opportunity for an attacker to potentially infiltrate tens or hundreds of thousands of different hosts.
So what actions should be taken to prevent an attack of this type?
- Vendor and Library Assessment: it’s necessary to carefully evaluate every library (whether open-source or commercial) before integration, checking the maintainer’s reputation;
- Secure Development Practices: adopt the NIST SSDF framework to define security requirements and automatic scans with tools like Dependabot or Snyk, and integrate code signing tools to ensure the distributed software has not been tampered with during the build or distribution;
- Immediate Practical Solutions: use Sigstore and Cosign for code signing in CI/CD pipelines to sign containers and binaries.
Conclusions: Trust is Good, Control is Better
Trust in the open-source world is certainly fundamental, but it must be paired with robust security practices, like pinning or tools like Dependabot that verify the dependencies used.
In your opinion, will attacks like this become the new normal in the open-source world?
Protecting the software supply chain isn’t an option, it’s a necessity. If the security of your CI/CD pipelines is a priority and you want to understand how to implement robust strategies like those described in this article, visit my portfolio to discover how I can help you.
