Reachability Analysis for Vulnerability Prioritisation, Explained
Reachability analysis is the discipline that asks whether a vulnerable code path can actually be invoked by the application, rather than treating the mere presence of a vulnerable component as sufficient evidence of risk. It is the noise-reduction layer that sits between component inventory (the SBOM) and exploit-relevant prioritisation (CVSS, EPSS, KEV, and VEX). For internal AppSec teams, vulnerability management teams, product security teams, and security engineering teams operating thousands of open SCA findings per quarter, reachability is often the highest-leverage intervention available because most published CVEs in transitive dependencies are not on a path the application actually executes. This guide covers what reachability analysis is and is not, the four operational tiers from manifest to runtime, how reachability composes with CVSS, EPSS, KEV, and VEX, the common pitfalls (overcalling, undercalling, transitive blind spots, reflective invocation, stale evidence), how the evidence reads inside an audit, and a four-week rollout that wires reachability into the existing vulnerability management lifecycle.
What Reachability Analysis Actually Is
Reachability analysis is a static or dynamic technique that determines whether a vulnerable code path in a third-party component can be invoked by the application. The classical software composition analysis (SCA) signal is component-level: a CVE appears in a package version, the package is in the dependency tree, and the SCA tool emits a finding. Reachability analysis adds the next question: is the vulnerable function on a path from any application entry point, or does it sit in a module the application never imports, never calls, or never exercises in production?
The motivation is throughput. Empirical studies of enterprise SCA programmes consistently report that the majority of CVE-tagged findings live in transitive dependencies, that most transitive vulnerabilities are not on a reachable code path for the consuming application, and that the AppSec triage queue is more often throttled by noise than by remediation capacity. Reachability analysis is the filter that converts the long tail of unreachable findings into a documented exception class, so the open backlog reflects exposure rather than inventory.
The discipline is not new. The compiler and program-analysis literature has called this question call-graph reachability for decades. What is new is that the SCA ecosystem has finally caught up: most modern SCA tools, OSV-Scanner, several commercial ASPM platforms, and the OpenSSF Scorecard adjacent projects all now publish reachability signals in some form. The operational discipline is figuring out which signal you have, what it actually proves, and how to wire it into the prioritisation function so the SLA reflects exposure rather than presence.
The Four Reachability Tiers
Reachability is not binary. The signal lives on a four-tier spectrum, from weakest to strongest evidence. Each tier reduces noise but also adds analysis complexity and false-negative risk. Most enterprise programmes target tiers 2 and 3 as the operational sweet spot, with tier 4 reserved for high-stakes or high-noise paths.
Tier 1: Manifest reachability
The vulnerable package version appears in a manifest file: package.json, package-lock.json, yarn.lock, go.mod, go.sum, requirements.txt, Pipfile.lock, pom.xml, build.gradle, Gemfile.lock, Cargo.toml. This is the floor every SCA tool reports. Manifest reachability is necessary but not sufficient; it answers the question is the package present in the dependency tree without saying anything about whether the code is loaded, called, or executed. Programmes that stop at tier 1 carry the full SCA noise.
Tier 2: Package reachability
The vulnerable package is imported somewhere in the application code: an import statement, a require call, a using directive, an include. The vulnerable function may not be specifically invoked, but the package itself is loaded by the application. Tier 2 catches dead-code dependencies (a package listed in the manifest but never imported, common in monorepos and in projects that share a manifest across services). Tier 2 is achievable with simple lexical analysis on most languages and is widely supported.
Tier 3: Function-level static reachability
Static call-graph analysis traces a path from the application entry points (HTTP handlers, message consumers, scheduled jobs, CLI entry, public exported functions) to the vulnerable function inside the package. Tier 3 is the strongest static signal available without running the application. It requires a working call-graph builder for the target language: most mature for Java, JavaScript, TypeScript, Python, Go, Ruby, and C-sharp; less mature for C, C-plus-plus, Rust, and native binaries. Tier 3 has known false negatives around reflection, dynamic dispatch, plugin systems, eval-style constructs, and runtime code generation.
Tier 4: Runtime reachability
Production instrumentation, profiling, or runtime application security monitoring (RASP-style telemetry) confirms that the vulnerable function actually executes during real user traffic. Tier 4 is the strongest possible evidence: the function is on a path the application takes in production. It requires runtime telemetry infrastructure, sampling discipline so the instrumentation cost is bounded, and a feedback loop that updates the reachability state when traffic patterns shift. Tier 4 is more common in large internal AppSec programmes than in smaller security teams.
The tiers are not mutually exclusive. A mature programme runs tier 2 against the full backlog as the noise filter, tier 3 against high-CVSS or KEV-listed findings as the strong-static signal, and tier 4 against the highest-stakes paths where the cost of an unreachable misclassification is high. The operational decision is which tier sets the SLA and which tier sets the exception trigger.
Reachability vs VEX, SBOM, EPSS, and CVSS
Reachability analysis is a complementary signal that runs before the prioritisation function, not a replacement for any existing scoring. Each of the surrounding signals answers a different question, and the operational discipline is to sequence them correctly.
| Signal | What it answers | Reachability relationship |
|---|---|---|
| SBOM | What components are present. | Input. Reachability runs against the SBOM dependency graph. |
| CVSS | How severe the vulnerability is, in the abstract. | Independent. Reachability does not change CVSS; it changes the priority weight applied to CVSS. |
| EPSS | Probability of exploitation in the next 30 days, against the CVE. | Independent. EPSS is computed against the CVE; it cannot tell whether the code is reachable. |
| KEV | Whether the CVE has been observed exploited in the wild. | Independent. A KEV-listed CVE in an unreachable code path is still operationally lower priority than a KEV-listed CVE in a reachable path. |
| VEX | A producer-side declaration of affected/not-affected status. | Output channel. Reachability evidence often supports a VEX not_affected statement with vulnerable_code_not_in_execute_path or vulnerable_code_not_present justification. |
| CWE | The weakness class the vulnerability belongs to. | Independent. CWE classifies, reachability triages. |
The defensible composition is: SBOM produces the dependency graph, reachability analysis filters the graph to the subset that is actually invocable, and CVSS, EPSS, KEV, and CWE then rank the filtered set. The vulnerability prioritisation framework guide covers the multi-signal scoring function reachability plugs into; reachability is the noise-reduction layer that runs before the scoring function consumes inputs.
Static vs Dynamic Reachability
Tier 3 (static call-graph) and tier 4 (runtime telemetry) sit on opposite sides of a tradeoff. Static reachability is cheap, repeatable, runs in CI, and produces an artefact that can be pinned to a commit hash. It misses reflection, dynamic dispatch, runtime code generation, and any path that only materialises at execution time. Dynamic reachability is expensive, sample-dependent, requires production instrumentation, and only sees code that ran during the observation window. It catches every path the application actually takes.
The practical pattern is to use static reachability as the default signal and dynamic reachability as the corrective layer. Static analysis runs against every build; the output reads against the manifest and produces a tiered classification. Dynamic analysis runs against production for a sampling window, the output feeds back into the reachability database, and the reachability tier on each finding shifts when runtime evidence overrides the static conclusion. A finding flagged unreachable by static analysis but observed reachable in production gets promoted; a finding flagged reachable by static analysis but never observed in production after a long observation window gets demoted to a lower tier.
One trap to avoid: the static analysis call graph is only as good as the entry points it knows about. A static reachability tool that does not understand custom HTTP routing, framework-specific request handlers, message-queue consumers, or internal RPC boundaries will produce systematically false-negative reachability calls. The remedy is to teach the analysis the application entry points explicitly rather than relying on default-only configuration.
The Five Common Failure Modes
Reachability programmes fail in predictable ways. Recognising the failure modes early shortens the time between deployment and operating value.
1. Overcalling unreachable
The static call graph does not show a path to the vulnerable function, so the tool marks the finding unreachable. The application uses reflection, dynamic dispatch, plugin loading, runtime code generation, JSON-driven dispatch, annotation-based wiring, or framework conventions the static analysis cannot trace. The unreachable call is a false negative. Mitigation: allow-list the language and framework features the static analyser cannot fully model and require an additional signal (manual review, dynamic tracing, test coverage) before marking those findings unreachable.
2. Undercalling reachable
The analysis cannot prove unreachability, so the finding stays reachable, but the manifest contains a dead package, the import statement is in a code path that never executes, or the function is in a feature flag that has been off for years. The reachable call carries operational cost without operational value. Mitigation: pair the static analysis with code-coverage telemetry from test suites and from production sampling; demote findings whose code paths show no observed execution over a sustained window.
3. Transitive blind spots
The analysis covers direct dependencies and stops at one or two levels of the transitive graph. Most CVE-tagged components live deeper in the graph. The programme reports clean reachability against direct imports while the transitive frontier silently accumulates unfiltered noise. Mitigation: extend the call-graph traversal to the full transitive depth and budget the analysis cost against the size of the dependency tree rather than against direct-only imports.
4. Test code path miscount
The reachability analysis traces test fixtures, mocks, and dev-only utilities as if they were production code paths, marking findings reachable through test code that never ships. The finding queue inflates with reachable-only- in-tests classifications that fail audit reads. Mitigation: scope the entry points to production code, exclude test directories from the call-graph roots, and document the production boundary in the analysis configuration.
5. Stale reachability evidence
A reachability claim from last quarter is treated as durable evidence months later, after a refactor, a feature shipment, or a dependency upgrade has changed the call graph. The exception register defers a finding on stale grounds. Mitigation: rerun the reachability analysis on every meaningful build (release tag, mainline merge, dependency bump) and treat the analysis output as a per-build artefact rather than a per-finding annotation.
How Reachability Reads Inside an Audit
Reachability is most often consumed as audit evidence rather than as a standalone output. Three frameworks regularly read reachability claims through their vulnerability-management requirements.
- ISO 27001:2022 Annex A 8.8 (Management of technical vulnerabilities): expects a documented basis for the prioritisation decision. A reachability annotation that points to a call-graph artefact, an analysis tool name and version, an analysis date, and a per-finding classification reads as defensible evidence; a reachability claim with no supporting artefact reads as a tester preference.
- SOC 2 CC7.1 (System operations: detection of vulnerabilities): the criterion expects the entity to have implemented procedures for identification of new vulnerabilities. Reachability evidence that explains why a known vulnerability is being deferred satisfies the related CC7.2 activity (response and remediation) provided the supporting analysis is dated, sourced, and re-evaluated on a defined cadence.
- PCI DSS Requirement 6.3.1 (Identify and rank vulnerabilities): the requirement reads against the ranking methodology. Reachability is a valid input to the ranking provided the methodology document records how reachability is determined, what tiers are recognised, and how reachability composes with severity scoring.
- NIST SP 800-53 Rev. 5 (RA-5 Vulnerability Monitoring and Scanning): the control expects analysis of scan reports, including the legitimacy of vulnerabilities. Reachability analysis is one of the techniques that substantiates a not-applicable finding state; the control implementation record should document the technique, the tools, and the analysis cadence.
Programmes that treat reachability as a documented signal with an audit trail (per-finding decision, supporting artefact, analysis tool and version, date) clear audit reads cleanly. Programmes that mark findings unreachable in a spreadsheet with no supporting evidence struggle, particularly when the audit asks how the same finding would re-evaluate today after a release shipped two weeks ago.
Where Reachability Fits in the Vulnerability Lifecycle
Reachability does not live in one workflow stage; it touches detection, prioritisation, remediation, and exception management. The order below reflects the order findings actually move through a mature vulnerability lifecycle.
At detection
The SCA finding lands with a manifest-tier reachability default. The CI pipeline emits the finding to the workspace alongside the SBOM artefact and the call-graph artefact for the build under test.
At triage
The reachability tier upgrades from manifest to package or function-level based on the analysis output. The triage decision uses the reachability tier as a filter input alongside CVSS, EPSS, KEV, and engagement context.
At prioritisation
The SLA assigned to the finding reflects the reachability tier. A reachable high-CVSS finding inherits the standard high-severity SLA; an unreachable high-CVSS finding moves into the deferred class with a re-evaluation trigger on the next major release.
At exception management
Unreachable findings outside the standard SLA are documented in the exception register with the supporting artefact, the analysis date, and the re-evaluation trigger. The register feeds the audit read and the leadership cadence.
At verification
A retest after remediation runs against the same call-graph configuration and the same reachability tools so the closure read is comparable to the original triage read. Findings closed by upgrade rather than reachability shift count under closed remediated; findings closed by reachability demotion shift count under closed unreachable.
At leadership reporting
The reachability split is part of the programme dashboard: total findings, reachable findings, unreachable-but-tracked findings, exception register health, and the rate at which the reachability tier shifts on rebuild. The metric set communicates exposure rather than inventory.
Reachability Tooling Landscape
The tooling landscape has matured significantly across 2024 and 2025. The ecosystem now spans open-source projects, commercial SCA platforms, and ASPM (application security posture management) suites. The summary below is intended as an orientation; specific feature claims, language coverage, and pricing should be verified against current vendor documentation.
- Open-source signals. OSV-Scanner exposes call-graph based reachability signals for several languages. OWASP Dependency-Check provides component-level coverage with optional reachability extensions through community plugins. OpenSSF projects publish package-level metadata that several reachability tools consume.
- Commercial SCA with reachability features. Several mature SCA vendors now ship function-level reachability for their supported languages, with varying analysis depth, runtime telemetry hooks, and call-graph output formats.
- ASPM platforms with reachability orchestration. Several ASPM platforms aggregate scanner output across multiple SCA tools and normalise the reachability signal into a single risk graph. Reachability is one of several inputs the platforms blend with EPSS, KEV, and engagement context.
- SAST-side reachability adjacency. Static analysis tools that build a full application call graph can emit reachability evidence as a side effect even when the primary scanner role is SAST rule evaluation. Programmes already running Semgrep, CodeQL, or vendor SAST can sometimes reuse the existing call graph for reachability output.
- Runtime sources. APM, profiling, eBPF tracing, and runtime application security monitoring tools can supply tier 4 evidence by tagging which functions actually executed during a sampling window. The trip from runtime telemetry to reachability annotation is operational, not automatic, and most programmes engineer the link rather than buy it whole.
For buyers comparing dedicated platforms that integrate reachability orchestration with engagement workflows and a single workspace record, the SecPortal vs Apiiro and SecPortal vs Cycode comparisons cover the ASPM-side trade-offs, including how reachability orchestration sits alongside engagement, finding, and reporting workflows.
A Four-Week Rollout
A reachability programme can move from zero to operating in four weeks for a single language and codebase. The sequence below is a starting plan; teams with multiple languages, multi-repo estates, or large dependency graphs should expect to repeat the cycle per language family or per repository class.
- Week one: baseline. Pick a single representative repository. Run the existing SCA and SAST output through the chosen reachability tool. Record per-finding tier (manifest, package, function-level static). Compute the unreachable percentage; the baseline number shapes the operating value of the programme. Document the entry-point list, the analysis tool version, and the analysis configuration so the baseline is reproducible.
- Week two: wire the lifecycle. Capture reachability tier as a finding attribute alongside severity, CVSS, EPSS, and KEV. Update the prioritisation function so reachability tier shifts the SLA band. Decide which tiers trigger immediate work and which tiers move to the exception register. Document the policy.
- Week three: tighten the reads. Update the exception register template to require the reachability tier, the supporting artefact, and the re-evaluation trigger at decision time. Build the leadership dashboard view that splits open findings by reachability tier. Wire the daily or per-build reconciliation so reachability tiers refresh against the latest build rather than persist across releases.
- Week four: compose with the rest of the programme. Add reachability splits to the monthly programme review and the quarterly leadership read. Capture the framework mapping (ISO 27001 Annex A 8.8, SOC 2 CC7.1, PCI DSS 6.3, NIST 800-53 RA-5) in the policy document. Run a calibration pass on the first month of reachability-uplifted closures and tune the tier-to-SLA mapping against observed throughput.
Where Reachability Sits in the Wider Security Org
Reachability-aligned vulnerability management is one workflow inside a wider internal security organisation. It sits next to the daily operational discipline of the VM team, the engineering-side AppSec function, the GRC owner's evidence cadence, and the leadership reporting cadence the CISO produces.
For the find-track-fix-verify operator function, the workflow is the natural pairing with SecPortal for vulnerability management teams. For the AppSec function that triages SCA and SAST output for engineering ownership, SecPortal for AppSec teams covers the upstream. For product security teams shipping software with VEX statements supported by reachability evidence, SecPortal for product security teams covers the producer-side discipline. For the security engineering team building the analysis infrastructure, SecPortal for security engineering teams covers the platform-side reading path. For the CISO sponsoring the programme, SecPortal for CISOs covers how reachability-driven outcomes roll up into leadership reporting.
Pair the programme with adjacent operating reading. The vulnerability prioritisation framework guide covers the multi-signal scoring function reachability plugs into. The risk-based vulnerability management buyer guide covers how reachability sits inside the wider RBVM operating model. The SAST vs SCA code scanning explainer covers the upstream detection layers reachability filters. The vulnerability prioritisation use case covers the workflow shape that reachability feeds. The vulnerability acceptance and exception management use case covers the register where unreachable-but-tracked findings live.
Run Reachability-Aligned Vulnerability Management on a Single Record
Reachability programmes succeed or fail on the recordkeeping. The reachability tier on each finding, the supporting artefact reference, the analysis date, the re-evaluation trigger, the exception register membership, and the framework mapping all need to live on the same record so audit reads collapse into a query rather than into a multi-tool reconciliation.
SecPortal is built around a single engagement record: findings management with CVSS calibration and per-finding metadata for reachability annotations, code scanning via Semgrep SAST and SCA for the upstream detection layer, repository connections for the build-side integration that produces the reachability artefacts, the activity log for the timestamped chain of state changes across findings, scans, and team actions, compliance tracking with ISO 27001, SOC 2, PCI DSS, and NIST framework mappings, and AI report generation for the leadership read of the reachability split.
None of these features run reachability analysis as an internal scanner module: the analysis is the output of the chosen tool, not of the platform. What SecPortal does is keep the reachability tier, the supporting artefact reference, the lifecycle, the exceptions, and the framework mapping on the same record so the audit conversation collapses into a query rather than a multi-team scramble.
Scope and Limitations
This guide describes the operating shape of reachability analysis as it is consumed in mainstream enterprise vulnerability programmes. The tooling ecosystem evolves rapidly: language coverage, analysis depth, runtime telemetry integrations, and the precision-versus-recall tradeoffs of individual tools shift between releases. Specific feature claims, supported languages, and the empirical false-positive and false-negative rates of named tools should be verified against current vendor documentation and against benchmark exercises on the team's own codebase.
Reachability analysis is a complementary signal, not a replacement for any existing scoring model or for a complete vulnerability management programme. Programmes that adopt reachability as a noise filter while retaining CVSS severity, EPSS exploit-likelihood, KEV observed-exploitation, and a documented exception register are the ones that see durable operating value. Programmes that adopt reachability as a single decision rule without supporting governance tend to misclassify reflective and dynamic-dispatch paths and lose audit-read durability after the first major release.
Run reachability-aligned vulnerability management on SecPortal
Stand up the engagement record in under two minutes. Free plan available, no credit card required.