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.
  • Editable (-e), URL, and VCS installs are not scannable. They have no PyPI metadata to resolve, so they are forwarded to pip unscanned — each one is flagged with a stderr warning so the gap is visible.

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

Support

If pip-cve-gate saves you time, consider sponsoring the work. Sponsorship funds maintenance of the pre-install CVE gate fleet across ecosystems.


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.1.tar.gz (35.7 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.1-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pip_cve_gate-0.2.1.tar.gz
  • Upload date:
  • Size: 35.7 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.1.tar.gz
Algorithm Hash digest
SHA256 5a6aede96a748d3cea2499d5804943b261302bb97479fccbd73dcf63fea9bb14
MD5 15e8168b77c76c8cf4d0f6818cfb9667
BLAKE2b-256 5eb5437c9672fafcfea73c34dafbdb1e65675ee0bd4820749bcb99f441065770

See more details on using hashes here.

Provenance

The following attestation bundles were made for pip_cve_gate-0.2.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: pip_cve_gate-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 22.1 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8e7aba08f52b79af37b83a7e002e8ddad66203167a425e63fd8db15dae85f578
MD5 bb19166b6ac53c753e0ed19ef76235ce
BLAKE2b-256 18318f425667996d2a34e2429866077ab56ea26625b4f63c5edca21ddfd2e583

See more details on using hashes here.

Provenance

The following attestation bundles were made for pip_cve_gate-0.2.1-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