Free tool
pip-audit, as a report someone can sign off on.
Drop the JSON from pip-audit -f json or osv-scanner --format json. Get each advisory once — GHSA link, CVE aliases, severity and vulnerable range — with the version that fixes it, then copy a Markdown table for the pull request or send the report to whoever decides what ships.
5 vulnerable packages (1 critical, 1 high, 3 moderate) · 6 advisories
Publishes this report on Comma: one URL that opens without CI access, restricted to named people or your company’s email domain if you like, comments pinned to the exact advisory (“not reachable — we never call full_load”), and next week’s scan kept as a revision you can diff. Free, no card.
How the scan is read
- pip-audit writes
dependencies[], one per installed or pinned package, each withvulns[]ofid,aliases,fix_versionsand adescription, whose first sentence becomes the title. Packages with no vulns are counted as scanned, not listed. - pip-audit has no severity. Its advisories show as Unrated and link to the GitHub advisory — the GHSA alias when the id is a PYSEC — where the CVSS score lives. Nothing is guessed.
- OSV-Scanner writes
results[].packages[]. Each package’sgroupsmerge the ids one flaw is known by; the report shows a group once, GHSA id first, with severity from itsmax_severityCVSS score in the standard bands (9.0+ critical, 7.0+ high, 4.0+ moderate) or else the GitHub rating. - Ranges and fixes come from the OSV
affectedevents —introduced2.3.0 andfixed2.31.0 read as>=2.3.0 <2.31.0. The fix for a package is the highest fixed version across its advisories; if any advisory has no fixed version, the package reads “No fix yet”. - npm, pnpm and yarn audit JSON are read too, through the same parser as the npm audit viewer.
Getting the JSON
| What to scan | Command |
|---|---|
| requirements.txt | pip-audit -r requirements.txt -f json -o audit.json |
| Active virtualenv | pip-audit -f json -o audit.json |
| pyproject.toml project | pip-audit . -f json -o audit.json |
| poetry.lock / uv.lock / Pipfile.lock | osv-scanner scan source --format json -L poetry.lock > osv.json |
| Whole repo, every ecosystem | osv-scanner scan source -r --format json . > osv.json |
| CI, without failing the step | pip-audit -r requirements.txt -f json -o audit.json || true |
Both tools exit non-zero when they find something, which stops most CI steps before the file is used — hence the || true. Keep a separate gating step if the build should fail. On OSV-Scanner 1.x, drop the scan source subcommand.
The scan is the easy part
The work is the decision after it — upgrade now, pin a transitive version, or accept the risk because the vulnerable function is never called. That call usually belongs to someone who won’t open CI logs: the tech lead, the client, the auditor collecting evidence. Published to Comma, the report is one link they can read on a phone and comment on advisory by advisory, and an agent can publish it from the pipeline after every lockfile change. More in how to share a pip-audit report, sharing OSV-Scanner results and what the OSV format is.
Questions
- How do I get pip-audit output as JSON?
- Run pip-audit -r requirements.txt -f json -o audit.json to audit a requirements file, or plain pip-audit -f json -o audit.json to audit the active environment. JSON includes each advisory's description by default (--desc auto), and the report uses its first sentence as the title. pip-audit exits 1 when it finds anything, so add || true in CI if a later step needs the file.
- Why does every pip-audit advisory say Unrated?
- pip-audit's JSON has no severity field — each vulnerability is an id, aliases, fix versions and an optional description. The report links each one to its GitHub advisory, which has the CVSS score, and keeps it Unrated rather than guess. For severities in the file itself, run osv-scanner on the same lockfile: its JSON carries a max_severity CVSS score per advisory group.
- What does OSV-Scanner's JSON contain?
- results[] has one entry per scanned lockfile or directory; each package lists its OSV vulnerabilities and groups. A group is one flaw known under several ids — a GHSA, a PYSEC and a CVE for the same bug — so the report shows each group once, under its GHSA id when there is one, with the others as aliases.
- Does it only work for Python?
- No. OSV-Scanner covers PyPI, npm, Go, Maven, crates.io, RubyGems, Packagist, NuGet and more, and the viewer reads every ecosystem in the file. It also reads npm, pnpm and yarn audit JSON, the same as the npm audit viewer.
- Can I paste the result into a pull request?
- Yes. “Copy Markdown” gives a GitHub-flavored table — severity with CVSS, package and version, linked advisory, vulnerable range and the version to upgrade to — for a PR comment or $GITHUB_STEP_SUMMARY.
- Is my scan uploaded?
- No. The JSON is parsed and the report is built in your browser. It only leaves your machine if you click “Get a shareable link” and publish it to Comma — and then you choose who can open it.
Related: npm audit viewer · SARIF viewer · what CVSS scores mean · SBOM · all free tools