Skip to content

Repository files navigation

ReconScope

ReconScope is an import-only, local reconnaissance visualization application. It parses existing Nmap XML, Nuclei JSONL, Subfinder JSONL, and HTTPX JSONL output into a deterministic graph. It never executes scanners or makes network requests.

Checkpoint 1: parser foundation

The parser returns this JSON envelope:

{
  "schema_version": "1.0",
  "sources": [],
  "nodes": [],
  "edges": [],
  "metadata": {
    "node_counts": {},
    "edge_count": 0,
    "warnings": []
  }
}

Node types are organization, domain, host, service, and vulnerability. Edges are contains, hosts, exposes, and affects. Every imported observation retains its source filename, format, line number when available, field path, raw record, and a bounded excerpt.

Stable IDs make future snapshot comparison deterministic. For example:

domain:acme.test
host:app.acme.test
service:app.acme.test:443:https
vulnerability:app.acme.test:443:exposed-debug-endpoint

The bundled sample_data/before and sample_data/after directories use only reserved .test domains. They intentionally include duplicate observations, all four parser formats, a removed host, a fixed finding, a new finding, and a changed service version/technology for later checkpoints.

Run parser tests

This checkpoint uses only the Python standard library, so no scanner or network dependency is needed:

python3 -m unittest discover -s backend/tests -v

Programmatic usage:

from backend.app.models import ScanFile
from backend.app.parsers import parse_scans

graph = parse_scans([
    ScanFile(name="nmap.xml", path="sample_data/before/nmap.xml"),
])

Backend checkpoint

Install the local API dependencies in a virtual environment:

python3 -m venv .venv
.venv/bin/pip install -r requirements-dev.txt

Run the API locally:

.venv/bin/uvicorn backend.app.main:app --reload

The interactive API documentation is available at http://127.0.0.1:8000/docs. The backend stores snapshots in memory and loads only local files or uploaded content. It never executes scanners or makes outbound requests.

Risk scoring

ReconScope uses a transparent additive score for each vulnerability:

score = min(100, severity_points + exposure_bonus + evidence_bonus)

Severity points are info=0, unknown=5, low=20, medium=40, high=70, and critical=90. HTTPX evidence for a reachable HTTP/HTTPS service adds 10; Nmap evidence for an open service adds 5. A matched URL/target adds 5, and non-empty extracted results add 5. Each node exposes the component values in properties.risk_breakdown. Scores are highest observed finding scores, not CVSS values or probability estimates.

The graph endpoint accepts repeated query parameters such as:

/api/graph?severity=high&port=443&technology=React&domain=acme.test

Filtering returns the selected findings or services plus their connected organization/domain/host/service path so the result remains explainable.

Frontend checkpoint

The React/Cytoscape interface runs on port 5173 and loads the local API on port 8000 by default:

cd frontend
npm install
npm run dev

The center canvas is a Cytoscape compound graph. The left panel filters the current snapshot, the graph highlights a selected node's neighborhood, and the right panel shows normalized properties plus the exact source line or XML path and raw excerpt retained by the parsers.

Snapshot diff and reports

Use Compare samples to load the bundled before and after snapshots and compare them in one view. The diff keeps the current graph plus baseline-only fixed findings and removed assets, with visible NEW, FIXED, CHANGED, and REMOVED status styling. Select a status in the diff panel to keep only that change class and its explanatory parent path.

The backend comparison endpoint is:

POST /api/diff
{"before_snapshot_id":"snapshot-1","after_snapshot_id":"snapshot-2"}

Reports for the same pair are available as Markdown or HTML:

/api/report/markdown?before_snapshot_id=snapshot-1&after_snapshot_id=snapshot-2
/api/report/html?before_snapshot_id=snapshot-1&after_snapshot_id=snapshot-2

Architecture

flowchart LR
  UI["React + Cytoscape UI"] -->|"local HTTP only"| API["FastAPI API"]
  API --> STORE["In-memory snapshot store"]
  STORE --> PARSERS["Deterministic import parsers"]
  PARSERS --> SCANS["Nmap XML · Nuclei JSONL · Subfinder JSONL · HTTPX JSONL"]
  STORE --> DIFF["Diff + explainable risk scoring"]
  STORE --> REPORTS["Markdown / HTML reports"]
  FIXTURES["Bundled .test demo fixtures"] --> PARSERS
Loading

The backend has no database, worker, scanner process, or outbound network client. Snapshots are held in memory for the lifetime of the API process. The frontend is a static Vite release bundle served by a local Python static server in the Docker setup; running npm run build refreshes the checked-in bundle.

Docker quickstart

From a fresh clone:

docker compose up --build

Open http://localhost:5173. The API documentation is at http://localhost:8000/docs.

The complete demo path is:

  1. Click Load sample with Before snapshot selected.
  2. Expand the organization, domain, host, and service levels in the graph.
  3. Click a vulnerability and inspect its exact source evidence in the right panel.
  4. Click Compare samples to load the bundled before/after snapshots.
  5. Use the diff status cards to inspect NEW, FIXED, CHANGED, or REMOVED assets.
  6. Click Markdown or HTML under Export to open the comparison report.

ReconScope demo workflow

The bundled data lives in sample_data/before and sample_data/after. It uses reserved .test domains and contains duplicate observations plus intentional new, fixed, changed, and removed cases, so the workflow is deterministic and safe to run without owning scan output.

API documentation and local development

To run without Docker:

python3 -m venv .venv
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/uvicorn backend.app.main:app --reload

In a second terminal:

cd frontend
npm install
npm run dev

The interactive Swagger UI is available at http://127.0.0.1:8000/docs, and the OpenAPI schema is available at http://127.0.0.1:8000/openapi.json. The frontend defaults to http://localhost:8000; set VITE_API_BASE_URL when using a different local API port.

Validation

./.venv/bin/pytest -q
cd frontend && npm run typecheck && npm run build
docker compose config

ReconScope is intentionally import-only. It does not run Nmap, Nuclei, Subfinder, or HTTPX, and it does not make outbound requests. It is a local explanation and comparison surface for scan data that already exists.

About

ReconScope: explainable attack-surface graph for imported reconnaissance scan output

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages