Context-aware vulnerability prioritization with attack-path chaining. Self-hosted, no lock-in, swap any scanner.
Reachability ingests vulnerability scan results and re-scores them against a model of your environment - your topology, your controls, your crown-jewel data. It cuts the noise of a "critical and high" backlog down to what is actually exploitable in your stack, and it surfaces the dangerous chains that scanners miss: the two "mediums" that, strung together, reach your database.
Severity is a property of your environment, not of a CVSS score. Reachability treats it that way.
Run a scanner against a SaaS app and you get hundreds of findings, dozens flagged critical or high. Most teams then spend days manually asking, per finding: Is this even reachable? Is there a WAF in front of it? Does it actually touch sensitive data? Could it be chained with something else? That triage is slow, context-heavy, and rarely finished. So backlogs grow, and the genuinely dangerous combinations - a low-severity SSRF that pivots into an unauthenticated internal admin endpoint - stay buried under noise that was never exploitable to begin with.
- Downgrades noise. A critical SQLi behind a blocking WAF on every inbound path, or a dependency CVE on code no internet-facing path ever invokes, is re-scored down - with a written rationale for every move. Nothing is silently suppressed.
- Upgrades real risk. It models each finding as an attacker step (preconditions -> postconditions) and searches your environment graph for chains that reach sensitive assets. A chain of three mediums that ends at a crown-jewel datastore is reported as critical, regardless of the individual scores.
- Explains itself. Every re-score carries an auditable trail - which rule fired, which control or path or chain drove it. The explanation is the product.
- Self-hostable.
docker compose up. Runs on your servers, AWS, Azure, anywhere. No external SaaS dependency, no phone-home, no telemetry. - No lock-in. Free, open-source scanners are the defaults. Already pay for a premium scanner? Swap it in by changing one line of config. The reasoning engine never knows the difference.
- Config as truth. Stack context, scanner choices, and scoring policy are declarative files you own and version-control.
- No hand-holding. Anyone with the technical skills deploys it solo. No sales call, no customer-success manager, no license key.
- Deterministic and auditable. Scores are reproducible run to run. A security team can verify every decision.
Scanners Normalize Context Reasoning
(swappable) findings graph (yours) engine
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│ nmap │ │ common │ │ assets │ │ reachability │
│ ZAP │ ──────► │ finding │ ─────► │ controls │ ─────► │ + chaining │
│ Grype │ │ schema │ │ zones │ │ + policy │
│ (yours) │ └──────────┘ │ data │ └──────┬───────┘
└─────────┘ └──────────┘ │
▼
re-prioritized findings + attack chains
each with a written rationale
- Ingest context. A guided questionnaire plus uploads - SBOM (CycloneDX/SPDX), IaC (Terraform), diagrams-as-code - build a graph of your environment. IaC is treated as ground truth; questionnaire answers as lower-confidence.
- Scan. Pluggable adapters run your chosen scanners and normalize every result into one schema.
- Reason. The engine computes internet-reachability per finding, builds attack chains over the graph, then applies a declarative scoring policy to produce a contextual severity, a delta, and a rationale.
- Report. A re-prioritized list and a set of attack chains, each expandable to why.
Defaults are all open-source. To use a premium scanner you already license, change one line:
# config/environment.yaml
scanners:
port: nmap
dast: zap # -> burp-enterprise
sca: grype # -> tenableMost scanners need only a declarative YAML adapter (command + field mappings, no code). Complex ones get a small Python adapter. See docs: writing an adapter.
core/ graph model, reasoning engine, scoring - scanner-agnostic
adapters/ one folder per scanner; OSS defaults + _template scaffold
schema/ normalized finding model, context graph, adapter contract, scoring policy
deploy/ docker-compose, env examples
docs/ self-host guide, "write an adapter in 20 minutes"
The contracts everything is built against live in schema/:
01-finding-schema.md- what every adapter must emit02-context-graph-schema.md- the environment model the engine queries03-adapter-interface.md- the scanner swappability contract04-scoring-policy.md- declarative re-scoring rulescategories.md- vuln-class taxonomy with pre/postconditions and control mappings
Early development. The design contracts are stable; implementation is in progress. Built core-first: context graph and ingestion, then one scanner end-to-end, then the downgrade engine, then attack-path chaining, then live DAST and reporting.
Python core. Postgres for storage and graph traversal (recursive CTEs) behind a GraphStore interface - no heavyweight graph DB required to self-host, with room to add one for very large environments. Containerized, provider-agnostic.
Apache 2.0. Use it, host it, embed it, modify it. No lock-in by design.