Skip to main content

Refined. Secure. Connected. โ€” Reachability-aware dependency vulnerability scanner for Python

Project description

ReachGuard Logo

Refined. Secure. Connected.
Reachability-Aware Dependency Vulnerability Scanner for Python

PyPI Version GitHub Release Python 3.10+ ReachGuard Self-Scan License: MIT OSV.dev PyCG Powered


๐ŸŽฏ 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)

  1. Finds CVEs in Dependencies: ReachGuard reads your requirements.txt (or pyproject.toml / Pipfile.lock) and queries the open OSV.dev security database for known vulnerabilities.
  2. 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), and Pipfile.lock. Automatically resolves exact pins (flask==2.3.2) as well as unpinned or version-ranged dependencies (flask>=2.0) via importlib.metadata.
  • ๐Ÿ” AST Entry Point Detector: Automatically identifies if __name__ == '__main__' blocks and web route handlers (@app.route, @app.get, @router.post for 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-json exports, --output-sarif for GitHub Code Scanning, --output-html interactive dashboards, and --fail-on-reachable exit gates for build pipelines.
  • ๐Ÿช Pre-Commit Hook: Native pre-commit framework support โ€” block commits automatically if reachable CVEs are detected.

โš™๏ธ 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'

๐Ÿช Pre-Commit Integration

ReachGuard supports the pre-commit framework, letting you block commits automatically when reachable CVEs are found.

Setup

  1. Install pre-commit (if you haven't already):

    pip install pre-commit
    
  2. Add the following to your project's .pre-commit-config.yaml:

    repos:
      - repo: https://github.com/chaitanyabhujbal912006-afk/reachguard
        rev: main  # or pin to a specific release tag
        hooks:
          - id: reachguard
            args: ["requirements.txt", "--src", ".", "--fail-on-reachable"]
    
  3. Install the hooks:

    pre-commit install
    

From now on, every git commit will automatically run a ReachGuard scan. Commits are blocked if any REACHABLE CVEs are found.


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).
  --output-html TEXT      Write an interactive HTML dashboard report to this file.
  --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      โ”‚
                     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  1. Dependency Ingestion: Auto-detects dependency files and normalizes package names and exact pinned versions according to PEP 503.
  2. Advisory Resolution: Batch queries OSV.dev REST endpoints to retrieve known vulnerability data and extracts function targets using heuristic regex mining.
  3. Call Graph Generation: Invokes PyCG to construct a complete control-flow call graph of Python callables.
  4. AST Entry Point Mining: Walks repository ASTs to locate execution roots (if __name__ == '__main__', Flask/FastAPI route decorators).
  5. 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:

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. 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

reachguard-0.2.0.tar.gz (35.8 kB view details)

Uploaded Source

Built Distribution

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

reachguard-0.2.0-py3-none-any.whl (32.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: reachguard-0.2.0.tar.gz
  • Upload date:
  • Size: 35.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.9

File hashes

Hashes for reachguard-0.2.0.tar.gz
Algorithm Hash digest
SHA256 bd67cceea7e8a66ea017aad683bfb5b59eeac384f1c5cb124be7013c2506ca38
MD5 86da8e4e70c281836b814fffc89f08b1
BLAKE2b-256 da879fcdb382dac51368d494b5481c220b6c7de7a2098fe11eb2d010602268ba

See more details on using hashes here.

File details

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

File metadata

  • Download URL: reachguard-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 32.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.9

File hashes

Hashes for reachguard-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bb45d08d1bb38ff82624ec5cf965a9eebc596f5bee7e38f891e2dd7fd8996557
MD5 89570e4c87eb248b50c69c36a4cbfa4a
BLAKE2b-256 a4046617a08aa792f8a300580bd7154a9040166c930938c2102f9d801abd972b

See more details on using hashes here.

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