Safeguard
Supply Chain•

How do you use pip hash checking for ML requirements files?

pip hash-checking mode verifies each download against hashes you record. Here are the rules, the steps and the traps for large ML dependency trees.

Safeguard Security Team
3 min read

Add a sha256 hash to every pinned requirement and pip will refuse any download that does not match. That is hash-checking mode. It guards against remote tampering, but it requires exact pins and a hash for every dependency, including the ones pulled in indirectly.

What pip says by default

The pip documentation states that by default pip does no verification of the distributions it runs. Hash-checking mode uses hashes you store locally, attached to each requirement, to guard against remote tampering and network problems. It was added in pip 8.0.

The rules

According to the pip documentation:

  • Adding a hash to any requirement switches the mode on for the whole file. You can also force it with the require-hashes option, which is useful in deploy scripts.
  • Every requirement and dependency needs a hash. An unhashed dependency is an error, because a partly hashed file could let bad code in through the gap.
  • Every requirement must be pinned to an exact version with a double equals sign, or to a URL or path.
  • sha256 is recommended. md5, sha1 and sha224 are excluded.
  • A package can list several hashes, which helps when it ships wheels for several platforms.
  • The sha256 fragments in PyPI links check for corruption only. They do not count as your own recorded hashes.

Steps for an ML project

  1. Resolve the full dependency tree in a clean environment and freeze exact versions.
  2. Generate hashes for each file you need. Your lock tool or pip hash can produce them.
  3. Write them into the requirements file.
  4. Install with the require-hashes option in CI and in image builds.
  5. Re-generate on every deliberate upgrade, and review the diff.
numpy==2.1.0 \
    --hash=sha256:<hash for linux wheel> \
    --hash=sha256:<hash for macos wheel>
pip install --require-hashes -r requirements.txt

Traps specific to ML stacks

TrapWhat to do
Many wheels per package for CPU, GPU and OSInclude a hash for each wheel you actually deploy
Special index for GPU buildsUse the index URL carefully and see our dependency confusion post
Transitive dependencies missing hashesGenerate the file from a full resolve, not by hand
Unpinned notebook installsMove installs into the locked file
Source builds that fetch more at build timePrefer wheels where you can

The pip documentation also describes an option to install only binary distributions, which fails for packages without one. Some ML teams use it to avoid running build scripts during install, though the failures need handling.

What hashes do not tell you

A hash proves the file matches what you recorded. It does not say the package is free of known vulnerabilities. Pair it with scanning, and review the version you pin.

Where Safeguard fits

Safeguard provides SBOM and dependency scanning, so the exact pinned versions in your lock file can be checked for known vulnerabilities, with reachability analysis to separate what your code calls from what it does not. A free scan is at gold.safeguard.sh/scan.

Quick check

Do I need hashes for transitive dependencies?

Yes. The pip docs say every requirement and dependency needs a hash in this mode, or pip reports an error.

Does hash checking replace vulnerability scanning?

No. It detects tampering after you record a hash. It does not tell you whether a version has known flaws.

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.