Table of contents
Title
Table of content
Table of contents
Title

Reachability analysis

Updated

Reachability analysis is a software security technique that determines whether an application actually calls the vulnerable code inside a third-party component. It works on the execution path, not on the inventory: a dependency can be declared, installed and shipped without a single line of its flawed code ever running. The output is not another severity score. It is an answer to one question — can this code run here?

Fewer than 1,200 of the roughly 350,000 open-source vulnerabilities tracked in Fluid Attacks' vulnerability database have function-level reachability rules. That ratio is the real measure of how far function-level analysis currently extends, and it is why reachability analysis belongs in prioritization rather than in the decision to silence a finding.

This page covers what reachability analysis is, how static and dynamic approaches differ, how Fluid Attacks reports three reachability levels instead of a reachable/unreachable binary, what CISA and OWASP codify about execution paths, and where the technique stops being reliable.

What is reachability analysis?

Reachability analysis traces the execution paths of an application to establish whether the specific function, class or module affected by a known vulnerability is invoked from the code under assessment. A software package often carries several vulnerabilities while the application uses only a subset of its functions. The technique separates what an application contains from what it exercises, which is the distinction every dependency report flattens.

The scope can extend past direct dependencies. Most vulnerable code arrives through transitive dependencies — libraries pulled in by other libraries, several layers deep, which developers rarely choose and often cannot name. Reachability analysis follows those chains and reports which link leads to a vulnerable function.

What the technique does not do is prove exploitability. Reaching the vulnerable code is a necessary condition for exploitation, not a sufficient one: an attacker still needs a controllable input, a matching deployment, and no compensating control in the way. Nor does reachability analysis replace software composition analysis. It is the layer that gives SCA findings application context.

Why reachability analysis matters

Dependency scanning produces more findings than any team can act on, and severity labels do not order them usefully. Reachability analysis adds the one variable that changes vulnerability prioritization: whether the code in question executes in this application at all.

Dependency inventories report presence, not risk

A software bill of materials answers "what is in here." It cannot answer "what does this do here." Fluid Attacks' documentation on SCA states that pairing dependency scanning with static application security testing is what makes it possible to identify reachable vulnerabilities — cases where the dependency's insecure element is used by the product under evaluation.

Without that pairing, every declared package with an advisory becomes an alert of equal weight. Reachability analysis turns that flat inventory into an ordered queue.

The gap is large. An industry estimate reported by Dark Reading puts typical usage at 10% to 20% of imported code — one expert's figure rather than a measured constant, but the direction holds.

Severity labels inherit upstream assumptions

Scoring systems built for the general case pass their conservatism downstream. Fluid Attacks' analysis of severity scoring found that tools frequently inherit CVSS base scores from the NVD or vendor advisories and surface them without adjusting for reachability, exploitability or customer context, so the conservative assumptions baked into those upstream scores are passed through unquestioned (full argument here).

A concrete case sits in Fluid Attacks' database. CVE-2022-23848, a command injection flaw in an Alluxio Maven component, carries an original CVSS score of 9.8, critical, under v3.1. Fluid Attacks' adjusted CVSS v4.0 score for the same entry is 4.4, medium, with an EPSS of 1.21%. Same vulnerability, two very different remediation queues. Reachability analysis is the correction applied locally, against the code that will actually run.

Database entry showing reachability capability and adjusted severity

CVE-2022-23848 in Fluid Attacks' database: critical under CVSS v3.1 (9.8), medium under the adjusted CVSS v4.0 (4.4).

It changes what gets fixed first

Prioritization only matters if it moves remediation. In Fluid Attacks' State of Attacks 2026, built on 1,119,396 vulnerabilities reported across client systems during 2025, systems running the CI Gate reached a 72.2% remediation rate against 58% for systems without it. Reachability analysis gives that gate the discrimination it needs: a build should break on code that runs, not on a lockfile entry.

Reachability, presence and exploitability are not the same

Three claims get collapsed into one in most dependency reports, and each requires different evidence. Keeping them apart is what makes reachability analysis useful instead of just another label, and it is also what keeps a reachability analysis result from being read as a clean bill of health.

Claim

What it asserts

Evidence required

What it cannot tell you

Presence

A component with a known advisory is part of the build

Manifest or lockfile entry, resolved version, SBOM record

Whether any of its code is imported or run

Reachability

The application's code calls, or leads to, the vulnerable function

Call graph or runtime trace, with file path and line of code

Whether an attacker can control the input that gets there

Exploitability

An attacker can trigger the flaw in this deployment

Reachable path plus attacker-controlled input, matching runtime and configuration, no mitigation in place

How much the organization should care, which is a risk question

The three claims behind a dependency finding, and the evidence each one needs.

A CVSS score describes the second and third columns for a generic product, not for yours. The EPSS describes the probability of exploitation activity in the wild, again for the vulnerability rather than for your deployment. Reachability analysis is the only one of the three signals produced from your source code, which is why it belongs in the same view as the other two.

Diagram comparing reachable and high-EPSS vulnerabilities

Reachability and EPSS measure different things, so a vulnerability can be reachable, high-EPSS, both or neither.

Reading the middle column as if it were the right-hand one is the most common misuse of reachability analysis.

Reachability analysis at Fluid Attacks

Fluid Attacks runs static reachability analysis as part of its SCA scans and reports the result as a prioritization attribute inside its ASPM platform, not as a finding of its own. The design choice that follows is deliberate: it raises the priority of what it can confirm, never lowers the priority of what it cannot.

Three levels, and no "unreachable"

Fluid Attacks reports three reachability levels rather than a binary verdict, separating what was declared, what was imported and what was called.

Level

Condition in the code

Coverage

Effect on the priority score

Latent

The vulnerable dependency is declared in the package manager, but no file imports it

All CVEs and advisories from supported sources, languages and package managers

Maximum reduction

Potential

The dependency is declared and imported, but the affected function is not called

Same as Latent

Minor reduction

Reachable

The dependency is declared, imported, and that function is called from the code

Only the CVEs and advisories with a published reachability rule

No reduction

The three levels Fluid Attacks reports, and what each one does to a finding's priority.

The absent fourth label is the point. There is no "unreachable" state, because a missing path is a limit of the analysis, not a property of the application. Calling a finding unreachable turns an unknown into a reassurance, and teams act on reassurances.

What it looks like in practice

Reachability analysis is only actionable if it hands a developer a location rather than a verdict.

In the platform's Packages section, dependencies with advisories appear as Vulnerable and, where confirmed, carry a "Reachable" tag. Expanding the row and following the related vulnerability identifies the file path and the line of code that calls or leads to the affected function. The same finding appears in the Vulnerabilities section with its origin marked Inherited, plus an evidence screenshot of the code in context.

Packages view with a vulnerable lodash dependency tagged Reachable

In the Packages section, a vulnerable dependency confirmed as called carries the Reachable tag (CVE-2020-28500 in lodash).

Vulnerability detail locating the vulnerable call in index.js, line 24

The finding points to the file and line of code that call the affected function: index.js, line 24.

That is the difference between "upgrade lodash" and "line 24 of index.js calls the affected function." One is a ticket; the other is a fix, and reachability analysis is what produces the second kind.

Deterministic rules rather than probabilistic inference

Fluid Attacks' security researchers review advisories for third-party components and write rules that identify the use of each affected function in client code. The rules are published by ecosystem, and the changelog records each batch: Release 41, in October 2026, added 32 new reachability rules. Fluid Attacks' own comparison documentation records the resulting analysis as deterministic, against probabilistic approaches that infer likelihood of use.

The trade-off is explicit. A deterministic rule only fires for a vulnerability someone has modeled, so coverage grows one CVE at a time. What it buys is that a Reachable tag means a call was found, not estimated.

Where the technique stops: roughly 0.3% coverage

The reachability filter in Fluid Attacks' public database shows the real coverage of function-level analysis. In October 2026 it returned 1,154 supported, 344,698 not supported and 3,664 impossible, out of 349,516 vulnerabilities tracked across 15 ecosystems. Function-level analysis therefore applies to roughly 0.3% of tracked open-source vulnerabilities, and Latent and Potential classification carries the rest.

Reachability filter counts in the Fluid Attacks vulnerability database

Reachability filter in Fluid Attacks' database, October 2026: 1,154 supported, 344,698 not supported and 3,664 impossible, out of 349,516.

A second limit of the reachability analysis pipeline was published rather than quietly absorbed. In Release 32, Fluid Attacks narrowed runtime CVE detection for .NET, Node.js, Bun and Python after concluding that the manifest fields it relied on declare only compatibility, not what gets deployed — so a CVE raised from them could be a vulnerability that does not apply. Removing a detection source is the correction this technique demands, because its value rests on its positives meaning something.

The practice that decides the rest

Reachability analysis results expire. A dependency upgrade, a refactor or a new feature can turn a Potential finding into a Reachable one between two commits, which makes point-in-time analysis misleading by design.

Fluid Attacks reruns the analysis as the code changes and updates its vulnerability database every four hours. Since October 2026, reachability is the seventh criterion in the platform's priority configuration, next to the CVSSF and the other scoring inputs.

"Figure out the attack surface and make sure the tainted input can never reach what you are trying to protect."

— Rafael Ballestas, security analyst at Fluid Attacks, in Tainted love

Go deeper: Fluid Attacks' guidance on benchmarking AppSec tools explains why SCA comparisons should normalize findings by unique, actionable vulnerabilities rather than by duplicated dependency references.

How reachability analysis is done

Two approaches produce reachability evidence, and they fail in opposite directions. One reads the code; the other watches it run. Most mature programs use reachability analysis built on the first and confirm selectively with the second.

Static reachability analysis

Static reachability analysis examines the codebase without executing it, resolving imports and call sites to build a call graph that links application entry points to functions inside dependencies. It runs on every commit and needs no deployed environment, which puts it inside the SDLC early enough to stop a vulnerable call from reaching production.

Its blind spots are the parts of a program that only exist at runtime: reflection, dynamic dispatch, plugin loading, code paths selected by configuration or by data fetched from an external source. The model is an approximation, and approximations omit things.

Dynamic reachability analysis

Dynamic analysis instruments a running application and records which dependency code is actually loaded and executed under real conditions. It resolves exactly what static analysis has to approximate, cutting false positives in the process, and it can surface behavioral anomalies such as unexpected file access or outbound connections from a library.

The cost is coverage. A run only proves what the exercised paths did, so an unexercised path returns no evidence either way. Add instrumentation overhead, data volume and the difficulty of driving every input combination, and dynamic analysis becomes a verification tool rather than a continuous one.

Combining static and dynamic analysis

Dimension

Static

Dynamic

When it runs

Every commit, pre-deployment

On a running, instrumented build

Evidence produced

Call graph, file path and line of code

Executed call records under real conditions

Main blind spot

Runtime-only behavior: reflection, dynamic loading, config-driven paths

Paths not exercised during the run

Main cost

Approximation of a model

Instrumentation overhead and data volume

Best use

Continuous prioritization across the codebase

Confirming or escalating a specific finding

What each approach to reachability analysis can and cannot establish.

The combination works as a sequence, not a merge: static analysis sets the queue, and dynamic runs settle the cases where the queue is contested.

What the standards already say about execution paths

Reachability analysis is not a vendor concept. The question it answers is written into how government and standards bodies expect dependency risk to be communicated.

CISA's Minimum Requirements for Vulnerability Exploitability eXchange (VEX), published in 2023, defines a VEX document as a way for a supplier to state that a product is not affected by a vulnerability in one of its components.

One of the five permitted justifications for that status is Vulnerable_code_not_in_execute_path, defined as a case where "the vulnerable code (likely in [subcomponent_id]) cannot be executed due to the way it is used by [product_id]." That is reachability analysis written as a disclosure obligation, which is why its results belong in supplier communication and not only in a dashboard.

The complement is the software bill of materials, which supplies the inventory those documents annotate. The OWASP Top 10:2025 ranks software supply chain failures as A03 and reports the highest average incidence rate of any category, 5.19% in its contributed data, across 215,248 recorded occurrences.

OWASP instructs teams to track not just direct dependencies but their transitive dependencies, and to reduce attack surface by removing unused dependencies, features and components. Reachability analysis is how an organization finds out which dependencies those are.

Read together, the two standards describe one workflow: inventory the components, decide with reachability analysis, disclose with VEX.

Two cases that show what reachability analysis is for

Both cases below are failures of triage, not of detection. In each one the vulnerable component was identified fast, and the question reachability analysis answers — does this application run that code — was the one nobody could answer at speed.

Log4Shell (CVE-2021-44228). OWASP still lists the Apache Log4j remote code execution flaw among its example exploitable component vulnerabilities, and the 2021 response is the reference case for dependency panic: the library sat deep inside build artifacts, usually pulled in indirectly, and most organizations could not quickly establish where it was.

Function-level reachability analysis would not have made every instance safe — Log4Shell was widely exploited — but it is built for the question those teams spent weeks answering by hand (Log4Shell explained).

The 2025 npm compromise. In September 2025, 18 widely used npm packages with a combined weekly download count of around 2.6 billion were published with malicious versions after a maintainer account was phished.

As Fluid Attacks reported at the time, not all applications using the compromised packages were affected: exposure required a fresh install, or a package-lock.json created while the malicious versions were live (full analysis). Presence and exposure were, once again, different questions, and reachability analysis is what separates them before an incident forces the issue.

Challenges and limits of reachability analysis

Scale is the first constraint. Building call graphs across a large polyglot codebase consumes computation and time, and accuracy trades against speed: cheaper analysis raises both false positives and false negatives, which defeats the purpose of running reachability analysis at all.

Obfuscated, minified or proprietary code inside third-party dependencies resists tracing. So does anything the language resolves at runtime, which is why reachability analysis coverage varies by ecosystem rather than being uniform.

The result also decays. Every dependency upgrade can move an affected function in or out of the call path, so reachability analysis needs rerunning as the code and the advisory data change.

The limit that matters most is the one teams are tempted to ignore: a negative result is not proof of safety. It means no path was found by this analysis, with its known coverage gaps, at this moment.

Automated detection alone does not close that gap. In Fluid Attacks' benchmark of 36 third-party AppSec tools against a dataset of 1,201 vulnerabilities across 105 CWE categories, the best-performing automated scanner — Fluid Attacks' own — detected 22.7% of them at 99% precision, while a pentester found 89.6% at 100% precision. Reachability analysis orders the work; it does not finish it.

Conclusions

Reachability analysis answers a narrower question than most dependency tooling pretends to answer, and that narrowness is its value. It tells you whether your code calls the affected code, which is the difference between an inventory entry and a defect you can hand to a developer with a file path and a line number. That is vulnerability prioritization with evidence attached.

Used as a prioritization attribute, reachability analysis works. Used as a filter, reachability analysis quietly converts a coverage gap into a safety claim. The reachability analysis design worth copying is the one that only speaks when it has evidence: three levels instead of two, no "unreachable" label, deterministic rules with published coverage, and continuous reruns because the answer changes with every commit.

Frequently asked questions

Is reachability analysis the same as software composition analysis?

No. SCA identifies the third-party components an application includes and matches them against vulnerability databases. Reachability analysis is a layer on top that determines whether the application's code calls the vulnerable function inside those components. SCA tells you what you have; reachability analysis tells you what you use.

Does a "not reachable" result mean the vulnerability cannot be exploited?

No, and treating it that way is the main failure mode. A negative result means no execution path was found by that analysis, within its coverage and at that moment. Reflection, dynamic loading, configuration-driven behavior and unmodeled CVEs all produce false negatives. Fluid Attacks avoids an "unreachable" label for this reason and classifies findings as Latent or Potential instead.

Does reachability analysis replace CVSS and EPSS?

No, it complements them. CVSS describes severity for a generic deployment and the exploit prediction score estimates activity in the wild; neither looks at your source code. In Fluid Attacks' platform, reachability became the seventh criterion in the priority configuration in October 2026, used together with those scores rather than in place of them.

Does reachability analysis cover transitive dependencies?

It depends on the level. At Fluid Attacks, Latent and Potential classification covers every advisory from its supported sources, transitive dependencies included. Function-level Reachable detection currently tracks direct dependencies, and extending it beyond them is on the published roadmap. OWASP Top 10:2025 makes the governance case for tracking both.

Does Fluid Attacks use reachability analysis, and how much is covered?

Yes, as part of its SCA scans, with published coverage. Of the roughly 350,000 open-source vulnerabilities tracked in its database across 15 ecosystems, about 1,150 have function-level reachability rules. Latent and Potential classification applies to all supported advisories, and new reachability rules ship with each release.

Make reachability the tiebreaker, not the label

Our scanners and pentesters work from your source code, so a dependency finding reaches your team with the line that calls it rather than a severity score borrowed from someone else's deployment — the basis of our software supply chain security solution. Start free trial · Contact us

Get started with Fluid Attacks' SSCS solution right now

Reduce risk without slowing delivery

Reduce risk without slowing delivery

Fast and accurate results from one continuous security program powered by AI, scanners, and pentesters.

Fast and accurate results from one continuous security program powered by AI, scanners, and pentesters.

Prevent

Prevent

Prevent

Detect

Detect

Detect

Manage

Manage

Manage

Remediate

Remediate

Remediate