Skip to main content

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 pip-audit

and once with uv-audit 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 audit has no include-style selection flags, so --group, --extra, --all-groups, and --all-extras do not apply to uv.lock inputs (a warning is printed). It audits main dependencies, the default groups, and all extras.
  • uv audit lists an advisory once per identifier it is known by, so the same finding arrives as both GHSA-… and PYSEC-…. uv-audit collapses those into one row per advisory and keeps the dropped identifiers in aliases.
  • Findings come from a different advisory source than the requirements.txt/pyproject.toml path, so IDs and counts for the same project can differ between input kinds. Each finding carries its aliases so an ignore entry written as PYSEC-… still suppresses the advisory uv reports as GHSA-….

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 }}

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uv_audit2-0.4.0.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uv_audit2-0.4.0-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file uv_audit2-0.4.0.tar.gz.

File metadata

  • Download URL: uv_audit2-0.4.0.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for uv_audit2-0.4.0.tar.gz
Algorithm Hash digest
SHA256 9a167f36a18319decd7c84196ae50cb67a401eb66c6d823b8db760be3d61785a
MD5 bb5e4ce0b4bc2f6aa22cc0776bc47d90
BLAKE2b-256 184c1469f7a27c3a4d3d82d045989df5b8f74b7be7474eaa126c4bbd42ce1304

See more details on using hashes here.

Provenance

The following attestation bundles were made for uv_audit2-0.4.0.tar.gz:

Publisher: publish.yml on SpielerNogard/uv-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uv_audit2-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: uv_audit2-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 24.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for uv_audit2-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fe96d97b3bb0345e40790155b833e70c461da0247580ec3fd00eb48a5c512567
MD5 237d22f5237d8670d7d10ea8d521b575
BLAKE2b-256 b6767d67d5147a51d819fd973e473ef7083086e0d84a188f8717d6ea8e9d5de4

See more details on using hashes here.

Provenance

The following attestation bundles were made for uv_audit2-0.4.0-py3-none-any.whl:

Publisher: publish.yml on SpielerNogard/uv-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.4.1

2 files

This release

0.4.0 This release

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page