Generate a Python SBOM from the most complete source you have. For most teams that is the installed virtual environment or a lockfile, not a loose requirements file. The cyclonedx-bom package reads environments, requirements, Pipenv and Poetry, and uv can export CycloneDX straight from its lockfile.
Pick the source first
| Source | Tool path | Strength | Weakness |
|---|---|---|---|
| Installed environment | cyclonedx-py environment | Shows exactly what is installed | Only as good as that environment |
| Poetry manifest and lock | cyclonedx-py poetry | Reproducible from the repo | Needs the lockfile committed |
| Pipenv manifest and lock | cyclonedx-py pipenv | Same | Same |
| requirements.txt | cyclonedx-py requirements | Works for legacy projects | Only as complete as the file |
| uv lockfile | uv export with the cyclonedx1.5 format | No extra install | Preview feature, may change |
The cyclonedx-bom documentation says environment mode is the main route for PDM, uv and conda environments, because it does not list their manifests or lockfiles as supported inputs.
Steps
- Build the environment the way production does, in a clean virtual environment.
- Install cyclonedx-bom with pip, pipx or uv tool install. It needs a current Python 3.
- Run the matching subcommand.
cyclonedx-py environment > sbom.cdx.json
- For uv projects, export from the lockfile.
uv export --format cyclonedx1.5 --output-file sbom.json
- Validate and store the file with the build.
The requirements.txt problem
A requirements file often lists only your direct packages. If it is not a full pin of the tree, the SBOM misses transitive dependencies. Pip freeze prints every installed package pinned, but it omits pip itself, and on older Python versions setuptools and wheel, unless you ask for all. If those matter in your image, include them.
What uv adds
The uv export is lockfile based and, per its documentation, marked as preview. It carries custom properties for environment markers and for workspace paths. Treat the format as subject to change and pin your uv version in CI.
One more habit pays off. Record the Python version and the platform the environment was built on, either in the file's metadata or in your release notes. Some packages install different dependencies on different platforms or Python versions, so two environments built from the same requirements can produce different SBOMs. If you ship to more than one platform, generate one file per platform and label each clearly.
Try it yourself
Click through it at your own pace, or open it full screen.
Compare direct and transitive entries. If your file only shows the direct ones, your source is too thin.
Quick check
Is requirements.txt enough for an SBOM?
Only if it pins the full tree. Otherwise scan the installed environment or a lockfile.
Does the Python tool sign the SBOM?
No. The project says signing must be done externally.
Safeguard's SBOM and dependency scanning works from manifests and lockfiles, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.