Skip to main content

Pre-install CVE gate for pip — blocks vulnerable and freshly published packages before install

Project description

pip-cve-gate

Pre-install CVE gate for pip. Blocks vulnerable and freshly published packages before any code runs on your machine.

safe-pip install flask requests django
# [pip-cve-gate] Scanning 3 package(s)…
# [pip-cve-gate] Resolved 27 package(s) (incl. transitive deps)
# [pip-cve-gate] All clear — delegating to pip

If a package is blocked:

safe-pip install somelib
# [pip-cve-gate] BLOCKED — install aborted
#   [CVE] 'somelib==1.2.3' has known vulnerabilities: GHSA-xxxx-yyyy-zzzz
#   [FRESH_HOLD] 'dep==0.0.1' was published 1d ago (hold: 3d). Use --skip-fresh-hold to override.

Exit code 0 = clean, 1 = blocked, 2 = error.


Why

Post-install tools (pip-audit, safety) run after pip has already downloaded and potentially executed install scripts. By then it's too late for zero-hour supply chain attacks.

pip has no native plugin hook for pre-install scanning. pip-cve-gate fills that gap with a wrapper that resolves the full dependency tree, scans every package against three independent feeds, and only delegates to real pip when everything is clean.

The closest prior art — pipask — checks PyPI advisories but lacks freshness hold and OSSF malicious package coverage. pip-cve-gate covers all three.


What it checks

Signal Source Fail behaviour
Known CVEs / advisories OSV.dev + PyPI Advisory DB Block
OSSF malicious packages ossf/malicious-packages Block
Freshness hold (default 3d) PyPI upload timestamp Block (overridable)

Network failures fail open — a broken feed never blocks your CI.

Known limitations

  • Version resolution is not pip-compatible. For unversioned specs (safe-pip install flask), the gate scans the latest release on PyPI, not the version pip would actually pick under your existing constraints. Pin or use a requirements file with explicit specifiers (flask==3.0.0 or flask>=3,<4) when you need the scan to match what pip will install.
  • Environment markers are evaluated in the current interpreter. A dep gated by sys_platform == "win32" scanned on Linux will be skipped, just as pip would skip it.
  • PyPI JSON API has a 60 req/min rate limit. Caching dedups transitive lookups, but very large dep graphs may still hit it. Set GITHUB_TOKEN to lift the OSSF feed's 60 req/hour limit.

Usage

safe-pip is a drop-in replacement for pip install:

safe-pip install flask
safe-pip install "django>=4.2" "celery==5.3.6"
safe-pip install -r requirements.txt
safe-pip install flask --skip-fresh-hold   # bypass freshness hold only

Non-install subcommands pass through to real pip unchanged:

safe-pip list
safe-pip show flask
safe-pip uninstall flask

Install

pip install pip-cve-gate

Homebrew (macOS / Linux):

brew install sharkyger/tap/pip-cve-gate

Or run directly from the repo without installing:

git clone https://github.com/sharkyger/pip-cve-gate
cd pip-cve-gate
python bin/safe-pip install flask

Configuration

Variable Default Description
PIP_CVE_GATE_FRESH_HOLD_DAYS 3 Days a new release must age before install (max 365)
PIP_CVE_GATE_TIMEOUT 10 HTTP timeout in seconds (min 1, max 3600)
PIP_CVE_GATE_MAX_DEPTH 5 Max transitive dependency depth (min 1, max 50)
PIP_CVE_GATE_PIP_BIN pip Path to real pip binary
PIP_CVE_GATE_PIP_TIMEOUT (unset) Optional pip subprocess timeout in seconds; unset = no timeout
GITHUB_TOKEN (unset) Raises OSSF feed rate limit from 60 req/h to 5000 req/h

Cross-platform support

CI runs the full happy + fail-closed + arg-parse fix smoke loop on each release inside fresh containers for:

Distro Install path
Ubuntu (latest) apt-get install python3 python3-pip
Debian (stable-slim) apt-get install python3 python3-pip
AlmaLinux 9 dnf install python3 python3-pip
RHEL UBI 9 dnf install python3 python3-pip
macOS (Homebrew tap) system python3 + Homebrew formula

Tested on Python 3.9 – 3.12. Runtime dependencies: requests, packaging (both standard).

If you hit a distro-specific issue, open a PR with a fresh entry in scripts/ci-cross-distro.sh — the smoke loop is the source of truth.


Part of the safe-install fleet

pip-cve-gate is part of a pre-install CVE gate fleet for different package ecosystems:

Ecosystem Tool
Homebrew homebrew-safe-upgrade
Composer (PHP) composer-cve-gate
pip (Python) pip-cve-gate ← you are here

Contributing

Bugs / feature requests: open an issue or PR. Security issues: see SECURITY.md.

Local development:

git clone https://github.com/sharkyger/pip-cve-gate
cd pip-cve-gate
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pre-commit install
pytest -v
ruff check src/ tests/

License

MIT — see LICENSE.

Project details


Download files

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

Source Distribution

pip_cve_gate-0.2.0.tar.gz (31.9 kB view details)

Uploaded Source

Built Distribution

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

pip_cve_gate-0.2.0-py3-none-any.whl (20.3 kB view details)

Uploaded Python 3

File details

Details for the file pip_cve_gate-0.2.0.tar.gz.

File metadata

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

File hashes

Hashes for pip_cve_gate-0.2.0.tar.gz
Algorithm Hash digest
SHA256 501af9d86796fd4530737e96a58e9aab46db063ecb26f3b80e0deb9e7f82f14c
MD5 2bb4acf5f1d0510ea2d5861e47e2bac4
BLAKE2b-256 c9138df7ac66cf1db5d6fd0f25a0981804a10fe41fa509f17ee2ac53f5637666

See more details on using hashes here.

Provenance

The following attestation bundles were made for pip_cve_gate-0.2.0.tar.gz:

Publisher: publish.yml on sharkyger/pip-cve-gate

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

File details

Details for the file pip_cve_gate-0.2.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for pip_cve_gate-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43831bcf289e310953e9766a8eae26a050b28186f5c2f3de400c6bd54ff7da9b
MD5 936fc6eb7647da25b6c925ef03362246
BLAKE2b-256 a2d83f7acceb499900388bc721175eff8476dcd4eb7f4b00be30d330b0e7e4e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for pip_cve_gate-0.2.0-py3-none-any.whl:

Publisher: publish.yml on sharkyger/pip-cve-gate

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page