Safeguard
Developer Tools•

Python SBOM: generate from requirements.txt or the environment?

A Python SBOM from requirements.txt may miss transitive packages. Compare it with pip freeze or pip inspect to see what really got installed.

Safeguard Security Team
4 min read

A Python SBOM from requirements.txt is only as complete as that file. If it lists top level packages with loose ranges, transitive packages and exact versions are missing. Generating from the installed environment, or from a fully pinned file, gives a more accurate answer. Compare the two before you trust either.

Three sources, three levels of detail

Python projects keep dependency information in several places, and they are not equivalent.

SourceWhat it containsTypical gap
requirements.txt with rangesDirect packages and version rangesNo transitive packages, no exact versions
Fully pinned requirements fileEvery package at an exact versionNeeds to be generated and kept current
Installed environmentWhat is actually on disk after installReflects one machine and one moment

The pip documentation on repeatable installs explains why pinning matters. Pinning means using the == operator to require a specific version, and it notes that a requirements file of pinned versions can be generated with pip freeze, which pins the top level packages and all of their transitive dependencies. It also describes hash checking, where you add hashes to verify downloaded packages.

What the pip commands give you

The pip reference describes pip freeze as outputting installed packages in requirements format, listed in case insensitive sorted order. By default it leaves out bootstrap packaging tools, so on Python 3.12 and later pip itself is omitted unless you ask for everything. Know that before you compare counts: an SBOM and a freeze output can differ by those tools.

pip inspect, added in pip 22.2, produces a JSON report of the content of a Python environment. That is a richer starting point than a text list, because it describes installed distributions in a structured format.

A comparison you can run

  1. Create a clean virtual environment.
  2. Install from your requirements file.
  3. Run pip freeze and save the output.
  4. Generate an SBOM from the requirements file alone.
  5. Generate an SBOM from the environment.
  6. Compare package names and versions across the three.

Typical findings: the file based SBOM lacks transitive packages, shows ranges instead of versions, or lists a package that was never installed because of a platform marker. The environment based SBOM is fuller but tied to that interpreter and platform.

Choosing what to publish

  • For a library, publish the declared ranges in your metadata and an SBOM of a representative resolved environment.
  • For an application, build from a pinned and, where practical, hash checked file and generate the SBOM from that same set.
  • For a container, scan the image too, because system packages and Python packages share a filesystem.

Questions for any tool

  • Does it resolve ranges, or record them as written?
  • Does it read installed metadata from the environment, or only text files?
  • Does it handle projects that use other dependency files, such as a project metadata file or a lock file from another tool?
  • Does it say when a version is a range, so readers do not mistake it for an exact one?

Where Safeguard fits

Safeguard scans Python dependency files for vulnerable packages and produces an SBOM, with reachability analysis to separate called code from unused code. Run a quick check with the free scan at gold.safeguard.sh/scan.

Quick check

Why is my SBOM missing transitive packages?

Your requirements file probably lists only direct packages. Pin the full tree or generate from an installed environment.

Does pip freeze list everything?

It lists installed packages, minus bootstrap tools by default, so it is close to a full runtime record for that environment.

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.