Reachability Engine
A technical look at how Patchlynx constructs a call graph, maps CVE-affected functions to graph nodes, and determines whether a vulnerable function is reachable from your configured production entry points.
What is reachability?
A CVE describes a vulnerability in a function (or set of functions) within a package. A CVE is reachable if there exists a call path from any of your configured entry points to a vulnerable function. If no such path exists, the CVE is not reachable — it cannot be triggered by your code as deployed.
Patchlynx performs a conservative static analysis: if it cannot confirm that a path is absent, it marks the CVE reachable. False negatives (missed reachable CVEs) are more harmful than false positives.
How the call graph is built
- Entry point discovery — Patchlynx identifies your entry points from
package.json main, framework patterns, or your.patchlynx.yml. - AST-level import resolution — Every
import,require, andexportis resolved to a canonical file path. Dynamic imports are followed where the specifier is a string literal. - Function-level edge creation — Call expressions create directed edges from caller → callee function. Callbacks and event emitters are handled via pattern libraries per language.
- Transitive closure — The graph is expanded across package boundaries into node_modules (or site-packages, vendor/, etc.) following the same rules.
- CVE function mapping — NVD + language-specific advisory databases map CVE IDs to affected function names within package versions. These form the target nodes.
- Reachability query — For each CVE, we query: is the affected function reachable from any entry point? The answer (with path evidence) becomes the finding.
Advisory database sources
| Source | Languages | Refresh |
|---|---|---|
| NVD (NIST) | All | Hourly |
| GitHub Advisory Database | npm, pip, Maven, Cargo, Go | Real-time |
| OSV.dev | All | Hourly |
| npm Security Advisories | JavaScript | Real-time |
| RustSec | Rust | Daily |
Known limitations
We document these explicitly so you know where the analysis may produce conservative results (false positives) rather than false negatives:
- Dynamic imports with variable specifiers —
require(someVar)orimport(computedPath)are not fully resolved. Calls through these paths are treated as potentially reachable. - Reflection-based dispatch — Java's
Class.forName(), Python'simportlib.import_module(varName), and similar reflection patterns are handled conservatively. If the class/module name cannot be statically resolved, the CVE is marked reachable. - Post-bundling analysis — If you submit a bundled output (webpack bundle, esbuild output) rather than source, intra-bundle call resolution may be incomplete. We recommend pointing entry-point config at source files, not build output.
- Native extensions — C/C++ extension modules (
.nodebindings in Node.js) are analyzed by heuristic only. If a CVE is in a native addon, the reachability verdict is a best-effort approximation.