How to Scan Python Dependencies for Vulnerabilities
Every dependency in a Python project is a potential source of known security vulnerabilities. Scanning those dependencies against a vulnerability database catches problems before they reach production.
Using uv audit
uv 0.10.12 and later includes the uv audit command, which checks project dependencies against the OSV (Open Source Vulnerabilities) database.
Run it from the root of a uv project:
$ uv audit
uv audit reads the project’s lockfile and queries OSV for known vulnerabilities in each dependency. When vulnerabilities are found, it prints details with links to the relevant advisories and exits with a non-zero status code. When no vulnerabilities are found, it exits with status 0.
To emit the findings as JSON for scripts or dashboards instead of human-readable text, pass --output-format json.
To point uv audit at a custom vulnerability service instead of OSV, use the --service-url and --service-format flags:
$ uv audit --service-url https://vuln.example.com/api --service-format osv
Note
uv audit is in preview, and each run prints a warning that its interface may change; pass --preview-features audit to silence it. The base command requires uv 0.10.12 or later. Ignoring findings requires 0.11.3, adverse status reporting 0.11.9, and JSON output 0.11.15. Run uv self version to check, and uv self update to upgrade.
Ignoring a vulnerability
Not every finding is actionable: a fix may not exist yet, or the vulnerable code path may be unreachable from the project. Suppress a finding by passing its advisory ID. --ignore suppresses it unconditionally; --ignore-until-fixed suppresses it only while no fixed release exists, so the audit fails again once a patch is published.
$ uv audit --ignore CVE-2021-33503 --ignore-until-fixed GHSA-2xpw-w6gg-jr37
Both flags can be repeated, and both accept any alias for the advisory (CVE, GHSA, PYSEC, or OSV IDs). Ignoring by an alias suppresses every advisory record that shares it.
To persist ignores so CI runs apply them too, add a [tool.uv.audit] section:
# pyproject.toml
[tool.uv.audit]
ignore = ["CVE-2021-33503"]
ignore-until-fixed = ["GHSA-2xpw-w6gg-jr37"]If an ignored ID matches no finding in the project, uv audit prints a warning, which catches typos and entries that have outlived the vulnerable dependency.
Catching deprecated and archived dependencies
uv audit also reports adverse project statuses. PyPI’s project status markers (defined by PEP 792) let maintainers mark a project as archived (no further releases expected), deprecated (obsolete by its maintainers’ own judgment), or quarantined (locked by PyPI admins as unsafe). Dependencies carrying one of these statuses appear in the audit report:
$ uv audit
Resolved 2 packages in 1ms
Found no known vulnerabilities and 1 adverse project status in 1 package
Adverse statuses:
- pathlib is archived
An archived or deprecated dependency still installs and runs, but it will not receive security fixes. Treat the finding as a prompt to plan a replacement.
Auditing a self-contained script
To audit a single-file script with PEP 723 inline metadata instead of a project, pass --script:
$ uv audit --script demo.py
uv resolves the script’s declared dependencies and checks them against the same vulnerability database. No uv.lock is required.
Using pip-audit
pip-audit is an established alternative that also queries the OSV database. It works with any Python project, regardless of whether the project uses uv.
Run it as a one-off tool with uvx:
$ uvx pip-audit
This scans the packages installed in the current environment. To scan a requirements.txt file instead:
$ uvx pip-audit -r requirements.txt
Like uv audit, pip-audit exits with a non-zero status code when vulnerabilities are found.
Adding vulnerability scanning to CI
Both tools work well in GitHub Actions because they return non-zero exit codes on findings, which fails the CI step.
Here is a GitHub Actions workflow that runs uv audit on every push and pull request:
name: Vulnerability scan
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v8.2.0
- run: uv auditTo use pip-audit instead (for example, if the project uses an older version of uv or does not use uv at all):
name: Vulnerability scan
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v8.2.0
- run: uvx pip-audit -r requirements.txtLearn more
- How to Protect Against Python Supply Chain Attacks with uv covers dependency cooldowns and uv’s install-time malware checks.
- uv audit CLI reference
- pip-audit documentation
- OSV database