AReachability-Based Vulnerability Prioritization: Fixing What Actually Gets Exploited

The fundamental premise of vulnerability prioritization is that not all CVEs are equally dangerous in any given environment. A CVSS 9.8 CVE in a package that never executes in your application is less dangerous than a CVSS 7.0 CVE in a package that handles untrusted input in an internet-facing service. Reachability is the variable that makes this distinction explicit.

Reachability analysis determines whether the code path containing a vulnerability can be reached by an attacker—whether there exists a path from external input to the vulnerable function, through the application’s call graph, that an attacker could traverse. CVEs in reachable code paths are genuinely dangerous; CVEs in unreachable code paths are theoretical exposures that may never become real attacks.


The Reachability Gap in Standard Vulnerability Scanning

Standard vulnerability scanning operates at the package level: identify which packages are installed, check which package versions carry CVEs, report the CVEs. This is correct and necessary. It’s also insufficient for prioritization.

The gap: a package can be installed in a container and carry a CVE without the CVE being reachable in any real attack scenario. The vulnerable function may be in a code path that’s never called by the application. The package may be installed as a build-time dependency that’s inadvertently included in the runtime image. The package may be in the base OS but completely disconnected from the application’s execution environment.

Standard scanners report these CVEs the same way they report CVEs in packages that are actively used and directly exposed. The finding lists mix genuinely dangerous CVEs with unreachable ones, and triage must separate them manually—at whatever scale the finding list presents.

In container environments, the scale is significant. General-purpose base images include many packages as OS dependencies; a substantial fraction of them don’t execute during normal application operation. The proportion of unreachable CVEs in a typical container finding list is large enough that reachability analysis is not a marginal optimization—it’s the primary filter.


Two Approaches to Reachability Analysis

Static call graph analysis

Static analysis traces the application’s call graph from entry points—HTTP handlers, message consumers, background jobs—through the application code and into library calls. If the vulnerable function in a CVE appears in the call graph reachable from an entry point, the CVE is statically reachable.

Static analysis is thorough but not perfect: it can overestimate reachability (identifying paths that are called conditionally or never in practice), and it requires access to the application’s source code.

Runtime execution profiling

Runtime profiling records which packages, libraries, and executable files actually load during observed application execution—normal operation, startup, shutdown, error handling. Packages that don’t appear in any profiling run aren’t executing.

Runtime profiling is empirical rather than analytical: it records what actually runs, not what could potentially run. It’s accurate for the execution patterns that were observed, with the caveat that unusual execution paths that weren’t captured in profiling won’t appear in the profile.

The combination—static analysis to catch code paths that aren’t captured in profiling, runtime profiling to confirm what executes under normal conditions—provides the most accurate reachability picture. For most container vulnerability programs, runtime profiling alone is sufficient to make the primary prioritization distinction between executing and non-executing packages.


Reachability and Automated Removal

Container CVE exposure from packages that don’t execute represents unnecessary risk. The remediation path for unreachable packages is not prioritized remediation—it’s removal. If the package isn’t needed by the application, it shouldn’t be in the container image.

Automated vulnerability remediation pipelines that take runtime profiling output and produce hardened images with unused packages removed accomplish two things simultaneously: they eliminate the CVEs from the unreachable packages without any patching effort, and they reduce the container’s attack surface for future CVE disclosures.

This is the reachability dividend: CVEs in unreachable packages are eliminated through image minimization, not remediated through patching. The remediation cost is the image rebuild pipeline execution time. The CVE count reduction is immediate and doesn’t create future maintenance burden (as updated package versions would).

After unused packages are removed, the remaining CVE finding list contains only packages the application uses. Within this set, reachability analysis at the function level—whether the specific vulnerable function is called by application code—provides a second tier of prioritization.


Building a Reachability-Based Priority Stack

Tier 1 — Reachable + CISA KEV or high EPSS: CVEs in packages that execute at runtime, confirmed to be actively exploited (KEV) or with high near-term exploitation probability (EPSS > 0.1). These are genuine urgent findings.

Tier 2 — Reachable + high CVSS: CVEs in packages that execute at runtime with CVSS 7.0+ and no specific exploitation evidence. Remediate within standard critical/high SLA timelines.

Tier 3 — Reachable + medium/low CVSS: CVEs in packages that execute at runtime with lower severity. Address through planned maintenance cycles.

Eliminated — Not reachable: Remove the packages through image hardening. The CVEs disappear without patching. No priority tier needed.

This stack produces a finding list that’s a fraction of the raw CVE inventory—typically 10-30% of installed packages actually execute in specific container workloads. The priority queue contains only reachable findings, which is the only category where prioritization has a security impact.


Practical Steps for Reachability Integration

Profile representative execution scenarios. Runtime profiling for reachability should capture the full operational surface: normal request handling, error handling paths, background jobs, startup and shutdown sequences. Profiling only happy-path operation may miss packages used in error recovery.

Establish a profiling baseline before hardening. Profile the current production container image before removing any packages. This baseline is the reference for validating that the hardened image produces equivalent outputs and that nothing required by the application was removed.

Validate hardened images against the application test suite. After removing unreachable packages, run the full application test suite against the hardened image. Test failures indicate that a removed package was required for some execution path that wasn’t captured in profiling. Re-add the package, update the execution profile, and retry.

Update the reachability profile when the application changes. Significant changes to application code—new dependencies, new features that use different library functions—may change which packages are in the execution path. Rerun profiling when the application changes and verify that the hardened image still includes all packages required by the new code.

Track reachable CVE count as the primary finding metric. Total CVE count measures the theoretical exposure. Reachable CVE count measures the actual exploitable exposure. Report reachable CVE count by severity tier as the primary vulnerability metric; total CVE count as a secondary metric for inventory completeness.


Frequently Asked Questions

What is reachability-based vulnerability prioritization?

Reachability-based vulnerability prioritization is the practice of using execution context—whether a vulnerable code path can actually be reached in a specific deployment—as the primary filter before applying severity scores. A CVE in an unreachable package (one that’s installed but never loaded at runtime) cannot be exploited by an attacker regardless of its CVSS score, so it should be eliminated through package removal rather than remediated through patching. Only CVEs in reachable, executing packages represent genuine exploitation risk and belong in the prioritization queue.

How does reachability analysis work in container environments?

Reachability analysis in container environments uses two complementary approaches: runtime execution profiling (recording which packages actually load during observed application operation—normal use, startup, shutdown, error handling) and static call graph analysis (tracing which functions are reachable from application entry points). Runtime profiling is empirical and accurate for observed execution patterns; static analysis catches paths not exercised during profiling. For most container vulnerability programs, runtime profiling alone provides sufficient signal to make the core prioritization distinction between executing and non-executing packages.

Why does reachability-based vulnerability prioritization shrink the remediation queue so dramatically?

In typical container workloads, only 10-30% of installed packages actually execute during application operation. The remaining 70-90% are base OS dependencies, build-time tools included inadvertently in runtime images, and transitive dependencies of libraries for features the application doesn’t use. Reachability-based prioritization routes all CVEs in non-executing packages to automated removal rather than the remediation queue—eliminating them without patching. The priority queue that remains contains only reachable CVEs, which is the only set where remediation effort has actual security impact.

How do you validate a hardened container image after removing unreachable packages?

After removing unreachable packages through image minimization, validate the hardened image by running the full application test suite against it. Test failures indicate that a package marked as non-executing was actually required by a code path not captured in the profiling run—re-add the package, update the execution profile, and retry. Additionally, run the hardened image through the same functional scenarios used for profiling to confirm equivalent behavior. The profiling baseline established before hardening serves as the reference for validation: the hardened image should produce identical outputs for all profiled execution scenarios.


The Elimination Advantage

Most vulnerability prioritization frameworks help teams work through a fixed queue more efficiently. Reachability-based prioritization, combined with automated removal of unreachable packages, shrinks the queue itself—not just the order in which items are processed.

A remediation program that processes 50 reachable CVEs per month is more effective than one that processes 500 total CVEs per month if the 500 total CVE queue includes 450 unreachable findings that will never be exploited. Working on the right problems at any speed beats working on the wrong problems quickly.