Safeguard
Developer Tools•

Why does python setup.py install undermine pip hash checking?

Calling setup.py install or develop can download unchecked dependencies and bypass your hashes. Use pip with no-deps instead. Here is the reasoning.

Safeguard Security Team
4 min read

Because setuptools' deprecated install paths fetch whatever dependencies they think you are missing, without your hashes. Pip's secure installs guide warns that this can nullify your security work. Install your own project with pip and dependencies disabled, so the hashed requirements file stays the only source of third party code.

The failure mode

Picture a careful setup. You have a requirements file with pinned versions and sha256 hashes, and you install it in hash-checking mode. Then a final line in your Dockerfile or CI script installs the application itself:

python setup.py install

The pip guide describes what happens next. Calling setup.py install, setup.py develop, or easy_install will go out and download, unchecked, anything you missed in your requirements file. It adds that it is easy to miss things as a project evolves.

So the hashed list covers what you remembered to list. The deprecated command then quietly fills in the rest, from the network, with no hash check.

The fix from the pip guide

Install the project through pip and tell it not to resolve dependencies:

python -m pip install --no-deps .

For development, the guide gives the editable equivalent:

python -m pip install --no-deps -e .

With no-deps, pip installs only your project. Every third party package must already be present from the hashed requirements file. If you forgot one, the import fails loudly instead of a stranger package arriving silently.

Make missing dependencies visible

The side benefit is a useful failure. A missing dependency was always a bug in your requirements file. Now you find it in CI, not in production.

  1. Install hashed requirements first, in hash-checking mode.
  2. Install your project with no-deps.
  3. Run the pip check command, which reports installed packages with missing or incompatible requirements.
  4. Run your tests.

If step 3 reports a missing package, add it to the source requirements, regenerate hashes, and review the new entry.

How to find the problem in an existing repo

Search your build files for the old commands. Look in Dockerfiles, Makefiles, CI configs, tox files and shell scripts.

Search forReplace with
python setup.py installpip install with no-deps on the project directory
python setup.py developpip install with no-deps and editable mode
easy_installpip install, with hashes for third party packages

Another reason to move off direct setup.py calls: the pip build system documentation says pip builds through the standard build interface, using an isolated environment by default. Calling setup.py directly skips that arrangement and the build requirements declared in pyproject.toml. See what pip install runs from packages for the wider picture.

What to do in CI

Add a grep step that fails the build if any of those commands reappears. It takes one line and prevents a regression that would be hard to notice in review.

Safeguard's dependency scanning and policy gates can flag a pull request that adds a dependency you did not review, which complements the hash file. A free scan is available at gold.safeguard.sh/scan.

Quick check

Does pip install with no-deps skip my own dependencies' hashes?

It installs only the named project. Your dependencies come from the hashed requirements file you installed earlier, so they keep their hash checks.

Is easy_install still part of a safe setup?

The pip guide lists it among the deprecated interfaces to avoid when you want hash checking to hold.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.