Yes. pip-audit can read an unpinned requirements file, but it has to resolve the dependencies first, so the result reflects what would install today, not what is running in production. For a trustworthy scan, audit a fully pinned file or a lockfile, or audit the installed environment.
Definitions
Pinned requirement. An exact version, written as name==version.
Unpinned requirement. A range or a bare name, which lets the installer choose.
Resolution. The step where the tool works out which concrete versions satisfy all constraints.
What pip-audit supports
Per the project page, pip-audit scans Python environments for packages with known vulnerabilities. It can audit the current environment, requirements files, local project paths such as pyproject.toml, and lock files. Output can be columns, JSON, Markdown or a CycloneDX SBOM.
By default it queries the Python Packaging Advisory Database through the PyPI JSON API. You can choose OSV as another service.
Decision table
| Your input | What happens | Trust level for production |
|---|---|---|
| Requirements with exact pins and hashes | No resolution needed with the hash option | High |
| Exact pins, no hashes | Skip resolution with the no deps option | Good |
| Loose ranges | Resolution runs, picks versions now | Lower, may differ from what you deploy |
| The live environment | Audits what is installed | High for that machine |
Steps
- Generate a fully pinned file from a known good environment.
- Audit that file.
- Store the audit in CI so it runs on each pull request.
- Treat exit code 1 as a failed check.
pip-audit -r requirements.txt
pip-audit -r requirements.txt --no-deps
pip-audit -r requirements.txt --require-hashes
Exit code 0 means no known vulnerabilities were found. Exit code 1 means at least one was found. The project says the exit code cannot be suppressed, so teams that need to continue use a shell construct such as an or true fallback.
About the fix option
The tool has a fix option that upgrades vulnerable packages, and a dry run mode that just reports what it would change. Use the dry run first, then run your tests.
Making the input trustworthy
A requirements file written by hand often lists a handful of top level names. That is a manifest, not a record of what runs. To turn it into a record, install it in a clean environment, test it, and write out the exact versions with pip freeze. The pip documentation notes that freeze reports what is installed in name==version form. It does not compute a solver result, so treat it as a snapshot of that environment.
Audit that snapshot, commit it, and update it deliberately when you change dependencies. The audit then answers a precise question: does what we run match a known advisory?
When to audit the environment instead
If you ship a virtual environment or a container, audit the environment itself. It reflects the real installed set, including packages that were pulled in by other tools. Pair that with an audit of the pinned file in CI so you catch problems before the image is built.
Quick check
Why did my scan differ from production?
If the file was unpinned, pip-audit resolved fresh versions. Production may be running older ones.
Does a clean result prove I am safe?
No. It means no known advisory matched at that moment.
Safeguard scans Python manifests as part of dependency scanning and flags reachable findings. Try the free scan.
Sources
Last reviewed: 19 October 2026.