PyPI
Python Package Index
The Python package registry that pip installs from by default.
About
PyPI is the public registry for Python packages, and pip installs from it by default. Web apps, data science and AI code all lean on it heavily. Anyone can publish there, and names go to whoever claims them first, so a name alone does not show who wrote the code.
A package published as source can run its build code during pip install, with the rights of whoever installs it. Everything else runs inside the app whenever it imports the package.
If It Is Malicious
If a PyPI package is malicious, it runs inside a Python app with the app's rights, on every developer laptop and build server that installs it.
See It in the StackExamples
These are well-known names from PyPI, written as you would meet them in an inventory, an alert or a lockfile, the file that records every version a build installed.
requests- The usual way Python code makes HTTP calls.
urllib3- The HTTP library under requests, installed without anyone asking for it.
django- The Django framework, installed with pip like any other package.
numpy- Number crunching that much data science and AI code relies on.
boto3- The AWS SDK for Python.
How Bad Code Gets In
These are the ways bad code can reach your systems through PyPI. None of them needs a flaw in your own code, so outside code needs checking as much as your own.
- A package named like a popular one catches mistyped installs.
- A public package shadows one from a private or extra index, as happened to PyTorch.
- A maintainer's account or token is stolen and a bad release is uploaded.
- A project's own release workflow is abused, so its real pipeline publishes bad code.
How to Check
These checks show what came from PyPI, whether a known bad version is in use, and how to keep one out next time.
- Pin exact versions with hashes, and install with pip's hash checking turned on.
- Run
pip-audit, which checks your requirements against known advisories. - Use one index, or a private mirror of PyPI, rather than adding an extra index beside it.
- Check a release's attestations on PyPI, which name the repository and workflow that published it.
Well-Known Incidents
Each incident below is a real case, told at the level of its public advisory. The tag says how the bad code got in, and the link opens the primary source.
Typosquat2017
Typosquats on PyPI
Slovakia's National Security Authority found ten PyPI packages with look-alike names, such as urlib3 for urllib3, that ran extra code when installed.
Reach Anyone who mistyped a name ran the extra code, which sent the user name and the machine's name back. PyPI removed the packages.
Affected
Source: sk-cert.sk (opens in a new tab)urlib3setup-toolsdjango-serverDependency Confusion2022
PyTorch
torchtritonA package on PyPI took the name of a dependency that PyTorch nightly builds fetched from PyTorch's own index, and pip installed the PyPI copy instead.
Reach Linux machines that installed PyTorch nightly builds with pip between 25 and 30 December 2022 got the fake package. Once code imported it, it sent system details and files, SSH keys included, to the attacker.
Affected
Source: pytorch.org (opens in a new tab)torchtritonCompromised Build or Release2024
Ultralytics
Attackers abused the project's own GitHub Actions workflow, so its normal release process built and published versions that carried a cryptominer. Two more followed through a leftover publishing token.
Reach Anyone who installed or upgraded the popular AI vision library in those days got the miner. The first two bad releases came from the real pipeline, so their provenance looked like any genuine release's.
Affected
Source: blog.pypi.org (opens in a new tab)ultralytics
In Common Stacks
These common stacks take code from PyPI. Open one to see where that code sits among its layers and who runs each one.