Yes. The pip documentation says that by default pip does no tamper checks and runs code from the distributions it installs. A source distribution is built with a build backend before it installs. Using binary wheels only reduces that, but it does not make a package safe to import.
Source distributions versus wheels
A wheel is a prebuilt archive that pip unpacks. A source distribution has to be built first, and pip works out its metadata using the project's build backend. That build step is code, and it comes from the package.
You can tell pip to refuse source distributions. Run this command, and any package without a wheel will fail to install, which is the point:
pip install --only-binary :all: -r requirements.txt
The pip reference describes this option as: do not use source packages, and packages without binary distributions fail to install.
Add hashes to catch tampering
Version pins say what you want. Hashes say exactly which file you want. In hash-checking mode every requirement, including dependencies, needs a sha256 hash and must be pinned with a double equals sign, a URL or a file path. A modified file or a malicious index then fails verification.
The documentation is careful about one thing: the sha256 fragment PyPI shows in a download link only checks for corruption. It does not count as your tamper guard.
What this does not protect against
Hash checking proves the file matches the one you approved. If you approved a malicious package, you have a verified malicious package. So the two controls answer different questions:
| Control | Question it answers |
|---|---|
| Wheels only | Will I run package build code at install? |
| Hash pinning | Is this the same file I reviewed? |
| Review before adding | Should I trust this package at all? |
Wheels also do not stop import-time code. Once your program imports the module, its code runs.
Why a clean environment still matters
Even with wheels and hashes, assume the code will run at some point: at import, in tests or in production. Install into a fresh virtual environment, keep long-lived credentials out of the shell that runs the install, and avoid installing as an administrator. If a package misbehaves, the damage stays inside a disposable environment.
A sensible baseline
- Pin requirements with hashes in the file CI uses.
- Use wheels only, and make exceptions for the few source builds you review.
- Use a single trusted index for private names. See why extra-index-url is risky.
- Install in a clean environment without secrets.
Quick check
Is a wheel always safe?
No. A wheel avoids a source build at install time, but its Python code still runs when imported. A wheel can be malicious.
Should I run setup.py install directly?
The pip documentation advises against calling setup.py install or develop directly, because they can download unchecked dependencies. Use pip install with no dependencies for your own project instead.
Safeguard does SBOM and dependency scanning for Python projects, and there is a free scan if you want to see your tree.
Sources
Last reviewed: 19 October 2026.