uv-audit
pip-audit like vulnerability scanning but fast
My example requirements.txt:
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml -o runtime/requirements.txt
annotated-types==0.7.0
# via pydantic
anyio==4.9.0
# via starlette
cachetools==5.5.2
# via google-auth
certifi==2025.4.26
# via requests
charset-normalizer==3.4.2
# via requests
click==8.2.1
# via
# flask
# functions-framework
cloudevents==1.12.0
# via functions-framework
deprecation==2.1.0
# via cloudevents
fastapi==0.115.12
# via availability-profile (pyproject.toml)
flask==2.2.5
# via
# functions-framework
# vellox
functions-framework==3.8.3
# via availability-profile (pyproject.toml)
google-api-core==2.25.0
# via
# google-cloud-core
# google-cloud-firestore
google-auth==2.40.3
# via
# google-api-core
# google-cloud-core
# google-cloud-firestore
google-cloud-core==2.4.3
# via google-cloud-firestore
google-cloud-firestore==2.21.0
# via availability-profile (pyproject.toml)
googleapis-common-protos==1.70.0
# via
# google-api-core
# grpcio-status
grpcio==1.72.1
# via
# google-api-core
# grpcio-status
grpcio-status==1.72.1
# via google-api-core
gunicorn==23.0.0
# via functions-framework
idna==3.10
# via
# anyio
# requests
itsdangerous==2.2.0
# via flask
jinja2==3.1.6
# via flask
markupsafe==3.0.2
# via
# jinja2
# werkzeug
packaging==25.0
# via
# deprecation
# gunicorn
proto-plus==1.26.1
# via
# google-api-core
# google-cloud-firestore
protobuf==6.31.1
# via
# google-api-core
# google-cloud-firestore
# googleapis-common-protos
# grpcio-status
# proto-plus
pyasn1==0.6.1
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.2
# via google-auth
pydantic==2.11.5
# via fastapi
pydantic-core==2.33.2
# via pydantic
requests==2.32.3
# via google-api-core
rsa==4.9.1
# via google-auth
sniffio==1.3.1
# via anyio
starlette==0.46.2
# via fastapi
typing-extensions==4.14.0
# via
# fastapi
# pydantic
# pydantic-core
# typing-inspection
# vellox
typing-inspection==0.4.1
# via pydantic
urllib3==2.4.0
# via requests
vellox==0.1.3
# via availability-profile (pyproject.toml)
watchdog==6.0.0
# via functions-framework
werkzeug==3.1.3
# via
# flask
# functions-framework
scanned once with pip-audit
and once with uv-audit
uv-audit needs 0.852s and pip-audit needs 4.617s total to scan the same requirements.txt file. I expect the time to diverge even more with larger requirements files or when using multiple requirements files.
Usage
Install:
uv pip install .
Audit a requirements file:
uv-audit -r requirements.txt
Audit a pyproject.toml (main dependencies only):
uv-audit -r pyproject.toml
Audit a uv.lock (delegated to uv audit):
uv-audit -r uv.lock
Include specific dependency groups and/or extras:
uv-audit -r pyproject.toml --group dev --extra cli
Include everything (all groups + all extras):
uv-audit -r pyproject.toml --all
Shortcut for a project directory (uses its pyproject.toml):
uv-audit ./my-project --all-groups
Mix files in one run:
uv-audit -r requirements.txt -r ./svc/pyproject.toml --all-groups
uv.lock inputs
uv.lock files are handed to uv audit --frozen, which reads the lockfile
as-is and queries its own vulnerability service (OSV). No virtual environment
is created and no PyPI lookups happen, so these scans are the fastest of the
three.
Three consequences:
uv audithas no include-style selection flags, so--group,--extra,--all-groups, and--all-extrasdo not apply touv.lockinputs (a warning is printed). It audits main dependencies, the default groups, and all extras.uv auditlists an advisory once per identifier it is known by, so the same finding arrives as bothGHSA-…andPYSEC-…. uv-audit collapses those into one row per advisory and keeps the dropped identifiers inaliases.- Findings come from a different advisory source than the
requirements.txt/pyproject.tomlpath, so IDs and counts for the same project can differ between input kinds. Each finding carries itsaliasesso an ignore entry written asPYSEC-…still suppresses the advisory uv reports asGHSA-….
uv audit requires uv 0.12 or newer.
Machine-readable output
Use --json to emit results as JSON on stdout (errors go to stderr). The
payload lists every scanned input — including clean ones — along with the
resolved groups/extras selection.
uv-audit -r pyproject.toml --all --json
Example output:
{
"vulnerable": true,
"inputs": [
{
"source": "/abs/path/to/pyproject.toml",
"kind": "pyproject",
"groups": ["dev"],
"extras": ["cli"],
"vulnerabilities": [
{
"package": "flask",
"version": "1.1.2",
"id": "GHSA-XYZ",
"fix_versions": ["2.0.0"],
"link": "https://example.com"
}
]
},
{
"source": "/abs/path/to/requirements.txt",
"kind": "requirements",
"groups": [],
"extras": [],
"vulnerabilities": []
},
{
"source": "/abs/path/to/uv.lock",
"kind": "lock",
"groups": [],
"extras": [],
"vulnerabilities": [
{
"package": "flask",
"version": "1.1.2",
"id": "GHSA-m2qf-hxjv-5gpq",
"fix_versions": ["2.2.5"],
"link": "https://example.com",
"aliases": ["CVE-2023-30861", "PYSEC-2023-62"]
}
]
}
]
}
For requirements.txt and uv.lock files the groups and extras arrays
are always empty so the shape is identical across input kinds. The aliases
array is populated for uv.lock findings and empty otherwise. Exit code is
non-zero when any vulnerability is found.
Quick recipes with jq:
uv-audit -r pyproject.toml --all --json | jq '.vulnerable'
uv-audit -r pyproject.toml --all --json | jq '.inputs[] | select(.vulnerabilities | length > 0)'
uv-audit -r pyproject.toml --all --json | jq -r '.inputs[].vulnerabilities[].id'
Install as a uv tool
From PyPI (package name is uv-audit2, CLI command stays uv-audit):
uv tool install uv-audit2
uv-audit -r requirements.txt
Or directly from git:
uv tool install git+https://github.com/SpielerNogard/uv-audit.git@main
uv tool run uv-audit -r requirements.txt
GitHub Action
uv-audit is also packaged as a reusable GitHub Action. The action discovers
pyproject.toml, requirements*.txt, and uv.lock files in your repo, scans each for
known vulnerabilities, posts a sticky comment on the PR with findings, and
fails the build (configurable) when non-ignored vulnerabilities are present.
Quick start (single job)
name: audit
on: [pull_request]
permissions:
contents: read
pull-requests: write
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: SpielerNogard/uv-audit@0.2.0
with:
ignore_vulns: |
PYSEC-2026-161
Inputs
| Input | Default | Description |
|---|---|---|
path |
. |
Root directory for discovery |
include |
**/pyproject.toml, **/requirements*.txt, **/uv.lock |
Newline-separated glob patterns |
exclude |
.venv, venv, .tox, node_modules, .git, dist, build, site-packages |
Path components or globs to skip |
ignore_vulns |
(empty) | Vulnerability IDs to suppress |
fail_on_vuln |
true |
Exit non-zero when non-ignored vulns are found |
pyproject_args |
--all |
Extra CLI args for pyproject scans |
uv_audit_version |
matches action tag | Version of uv-audit2 installed from PyPI |
comment_on_pr |
true |
Create/update the sticky PR comment |
github_token |
${{ github.token }} |
Token used for the comment API |
Outputs
| Output | Description |
|---|---|
vulnerable |
'true' or 'false' |
vuln_count |
Number of non-ignored findings |
ignored_count |
Number of ignored findings |
report_json |
Aggregated JSON report |
Private indexes
Composite actions inherit env: from the caller; pass any UV_* / PIP_*
environment variable to authenticate against private PyPI mirrors:
- uses: SpielerNogard/uv-audit@0.2.0
env:
UV_INDEX_URL: https://pypi.example.com/simple
UV_INDEX_USERNAME: ${{ secrets.PYPI_USER }}
UV_INDEX_PASSWORD: ${{ secrets.PYPI_TOKEN }}
Metadata
Release files for uv-audit2 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| uv_audit2-0.4.1.tar.gz | 24.6 kB | With provenance | Details for uv_audit2-0.4.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| uv_audit2-0.4.1-py3-none-any.whl | Python 3 | none | any | Details for uv_audit2-0.4.1-py3-none-any.whl |
Total release size: 48.8 kB
Release files / uv_audit2-0.4.1.tar.gz
| Download URL | uv_audit2-0.4.1.tar.gz |
|---|---|
| Size | 24.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c438b1d0e598dd7cc38113460e51f4e858af17e0c15f556c9e2d204507a62e6
|
|
BLAKE2b-256 checksum How to use checksums |
7d87d2f0d4d6793d29d1586826b2c213e4e9e0e4be276d9fce2a212453658535
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logRelease files / uv_audit2-0.4.1-py3-none-any.whl
| Download URL | uv_audit2-0.4.1-py3-none-any.whl |
|---|---|
| Size | 24.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cc5c2eba367e87d63d31063e321116b2f108cb259aa55449919c60adcb27f7ca
|
|
BLAKE2b-256 checksum How to use checksums |
143922a5ff33020a75842753a31ab81249075339512ef794315d861ea7f93308
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logSecurity for uv-audit2 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for uv_audit2-0.4.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.