Reachability-aware dependency vulnerability scanner for Python
Project description
ReachGuard ๐ก๏ธ
Reachability-Aware Dependency Vulnerability Scanner for Python
๐ฏ The Problem
Traditional dependency security tools (Dependabot, Snyk, Safety) flag hundreds of vulnerabilities simply because a package version is listed in requirements.txt. However, in real-world applications:
- >80% of flagged CVEs are completely unreachable because your application never imports or calls the vulnerable functions.
- Developers suffer from severe alert fatigue, leading to critical vulnerabilities being ignored amidst the noise.
- Enterprise reachability tools are expensive, proprietary, and require sending private code to external cloud SaaS platforms.
โจ The Solution
ReachGuard is an open-source, local-first, zero-cost vulnerability scanner that performs static call-graph reachability analysis. It traces your application's execution path from entry points down to external dependency calls to verify whether a vulnerable function can actually be reached at runtime.
[ Entry Points ] ---> [ AST Walk ] ---> [ PyCG Call Graph ]
โ
โผ
[ OSV Advisory ] ---> [ Target Mine ] ---> [ BFS Reachability Check ]
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ REACHABLE (Action!) โ
โ UNKNOWN (Review) โ
โ UNREACHABLE (Ignore) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ก How It Works (In 2 Simple Steps)
- Finds CVEs in Dependencies: ReachGuard reads your
requirements.txt(orpyproject.toml/Pipfile.lock) and queries the open OSV.dev security database for known vulnerabilities. - Traces Your Source Code: It walks your Python source code (
--src ./src), constructs a call graph via PyCG, and verifies: "Does your code actually call the broken function inside that package?"
๐ The 3 Statuses ReachGuard Gives You:
| Status | Meaning | Action |
|---|---|---|
๐ด REACHABLE |
Your code actually calls the vulnerable function! | Fix / Patch Immediately! |
๐ก UNKNOWN |
Package has a CVE, but advisory function details are sparse. | Manual Review. |
๐ข UNREACHABLE |
Package has a CVE, but your code never calls that function. | Safe to Ignore! |
๐ Real-World Example:
Suppose your requirements.txt contains `werkzeug==2.3.3` (which has CVE-2023-221 in `parse_multipart`):
- Dependabot: ๐ด "CRITICAL VULNERABILITY! Update Werkzeug!" (Even if your app never uploads files!)
- ReachGuard: ๐ข "UNREACHABLE โ Werkzeug has a CVE, but your code never calls parse_multipart()."
- ReachGuard: ๐ด "REACHABLE โ app.py::download() -> Flask.dispatch_request() -> werkzeug.safe_join()"
๐ Key Features
- ๐ฏ Smart Reachability Ranking: Classifies findings into:
REACHABLE๐ด: Vulnerable function is reachable from application entry points (High Priority).UNKNOWN๐ก: Package is imported but function-level advisory details are sparse (Manual Review).UNREACHABLE๐ข: Package contains a CVE, but the vulnerable code path is never called (Safe to Deprioritize).
- โก Zero-Cost & Local-First: Built entirely on free, open tools โ OSV.dev API (no API key needed) and PyCG (static analysis).
- ๐ฆ Multi-Format & Dynamic Dependency Support: Auto-detects
requirements.txt,pyproject.toml(PEP 621 & Poetry), andPipfile.lock. Automatically resolves exact pins (flask==2.3.2) as well as unpinned or version-ranged dependencies (flask>=2.0) viaimportlib.metadata. - ๐ AST Entry Point Detector: Automatically identifies
if __name__ == '__main__'blocks and web route handlers (@app.route,@app.get,@router.postfor Flask, FastAPI, Starlette). - ๐งน Noise & Stdlib Filter: Eliminates false positives by filtering standard library method references (
str.format) and template filter names (xmlattr). - ๐ CI/CD Integrated: Rich terminal formatting with severity levels (
CRITICAL,HIGH,MEDIUM,LOW),--output-jsonexports, and--fail-on-reachableexit gates for build pipelines.
โ๏ธ Installation
Option 1: Via PyPI (Recommended)
Install ReachGuard globally from PyPI:
pip install reachguard
Option 2: From Source
git clone https://github.com/chaitanyabhujbal912006-afk/reachguard.git
cd reachguard
pip install -e .
(Requirements include typer, rich, requests, and pycg)
๐ป Quick Start & Usage
1. Basic Scan (Auto-build Call Graph)
Provide your dependency file and source code directory. ReachGuard will automatically detect entry points and generate the call graph:
reachguard requirements.txt --src ./src
2. Scan using Pre-Built Call Graph
If you already generated a PyCG call graph JSON file:
reachguard requirements.txt --src ./src --call-graph callgraph.json
3. CI/CD Quality Gate Pipeline
Export findings to JSON and break the build if any REACHABLE vulnerabilities exist:
reachguard requirements.txt --src ./src --output-json report.json --fail-on-reachable
๐ค GitHub Actions Integration
Add ReachGuard as an automated security quality gate in your repository (.github/workflows/security.yml):
name: ReachGuard Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
reachguard-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Run ReachGuard Reachability Scan
uses: chaitanyabhujbal912006-afk/reachguard@main
with:
requirements: 'requirements.txt'
src: '.'
output_json: 'reachguard-report.json'
fail_on_reachable: 'true'
๐ CLI Reference
Usage: reachguard [OPTIONS] REQUIREMENTS_PATH
Arguments:
REQUIREMENTS_PATH Path to requirements.txt, pyproject.toml, or Pipfile.lock [required]
Options:
-s, --src TEXT Path to Python source directory for auto call-graph & entry points.
-g, --call-graph TEXT Path to pre-built PyCG call graph JSON file.
-o, --output-json TEXT File path to export scan findings as structured JSON.
--output-sarif TEXT Write findings in SARIF v2.1.0 format (for GitHub Security Code Scanning).
--fail-on-reachable Exit with non-zero status (1) if reachable CVEs are detected.
--suggest-fixes Display recommended pip upgrade patch commands for vulnerabilities.
--help Show this message and exit.
๐ Sample Terminal Output
ReachGuard scanning requirements.txt โ 21 pinned dependencies
Loaded call graph: callgraph.json (137 nodes)
Entry points detected: 2
ReachGuard Scan Results
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Package โ CVE / ID โ Severity โ Status โ Summary โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ werkzeug==2.3.3 โ GHSA-29vq-49wr-vm6x โ MODERATE โ REACHABLE โ Werkzeug high resource usage parsing... โ
โ werkzeug==2.3.3 โ GHSA-87hc-h4r5-73f7 โ MODERATE โ REACHABLE โ Werkzeug parsing multipart form data... โ
โ celery==5.2.7 โ GHSA-1234-abcd-5678 โ HIGH โ UNKNOWN โ Celery deserialization advisory โ
โ flask==2.3.2 โ GHSA-68rp-wp8r-4726 โ LOW โ UNREACHABLE โ Flask session Vary: Cookie header โ
โ jinja2==3.1.2 โ GHSA-q2x7-8rv6-6q7h โ MODERATE โ UNREACHABLE โ Jinja sandbox breakout via format โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary: 2 reachable | 1 unknown | 2 unreachable | 0 critical severity (total CVEs: 5)
! Action required: 2 CVE(s) are reachable from your code -- patch or mitigate these first.
๐ ๏ธ Architecture & How It Works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Dependency File Parser โ
โ (requirements / toml / lock) โ
โโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ OSV.dev API Query โ
โโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AST Entry Point Detector โ โ PyCG Static Call Graph โ
โ (__main__, @app.route) โ โ (Caller -> Callee Graph) โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Three-Tier BFS Engine โ
โ 1. Basename Match โ
โ 2. Path-Prefix Match โ
โ 3. Top-Level Entry Seed โ
โโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Rich Terminal & JSON โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- Dependency Ingestion: Auto-detects dependency files and normalizes package names and exact pinned versions according to PEP 503.
- Advisory Resolution: Batch queries OSV.dev REST endpoints to retrieve known vulnerability data and extracts function targets using heuristic regex mining.
- Call Graph Generation: Invokes PyCG to construct a complete control-flow call graph of Python callables.
- AST Entry Point Mining: Walks repository ASTs to locate execution roots (
if __name__ == '__main__', Flask/FastAPI route decorators). - Graph Traversal (BFS): Executes a multi-tier Breadth-First Search from discovered entry points to target vulnerability functions, returning a deterministic
ReachabilityStatus.
๐งช Running Tests
ReachGuard includes a 35-test suite covering AST parsing, OSV target extraction, noise filtering, call-graph normalisation, and reachability traversal:
python tests/test_suite.py
๐บ๏ธ Roadmap & Future Backlog
Interested in what's coming next or looking to contribute? Check out our detailed ROADMAP.md for planned features including:
- ๐ก Auto-Remediation Patch Advice (
--suggest-fixes) - ๐ก๏ธ SARIF v2.1.0 Export (
--output-sarif) - ๐ Interactive HTML Dashboards (
--output-html) - ๐ช Pre-Commit Git Hooks
- ๐ Extended Framework Detectors (Django, Celery, Click)
๐ค Contributing
Contributions are welcome! Feel free to open an issue or submit a pull request:
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
๐ License
Distributed under the MIT License. See LICENSE for details.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file reachguard-0.1.5.tar.gz.
File metadata
- Download URL: reachguard-0.1.5.tar.gz
- Upload date:
- Size: 25.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e6a9557202fc7cc6d16054e3b68784459685cf881f6f389757ad4e7923197a0
|
|
| MD5 |
840bdca2fa73466eeaf4828e1ab5006e
|
|
| BLAKE2b-256 |
c6745763bcb6a435f4f982e63d1c9d412514bdd7c8b8ccff86a55fc54aeab008
|
File details
Details for the file reachguard-0.1.5-py3-none-any.whl.
File metadata
- Download URL: reachguard-0.1.5-py3-none-any.whl
- Upload date:
- Size: 23.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25190612b3b18b3c5ad4cbebd04b8c06bd4d2263f175c08205b16bf0266a22c6
|
|
| MD5 |
908caf67ef2bbaf857ba6c7865b0d779
|
|
| BLAKE2b-256 |
56c0b30b6a3861e201cd170e7dff6f619c47ca26cb8f1ae251d785fc9f767e5e
|