Skip to main content

Dependencies & CVEs

Vulkro matches every dependency in your manifests and lockfiles, direct and transitive, against a local CVE bundle.

vulkro update # refresh the local CVE bundle
vulkro scan . # dependency CVEs are part of every scan
vulkro match-cve --sbom sbom.json # match an existing SBOM (CycloneDX or SPDX)

What is parsed​

EcosystemFiles
npmpackage.json, package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lock
PyPIrequirements*.txt, Pipfile, pyproject.toml, poetry.lock, Pipfile.lock
Gogo.mod, go.sum
crates.ioCargo.toml, Cargo.lock
Mavenpom.xml (including <dependencyManagement> and parent POMs inside the repository), gradle.lockfile
RubyGemsGemfile.lock
Packagistcomposer.lock
NuGet*.csproj, packages.lock.json

A Gradle project without gradle.lockfile gets source analysis but no dependency CVEs. Transitive hits are reported at Medium confidence and marked (transitive dependency); set VULKRO_SCA_NO_TRANSITIVE=1 to match declared dependencies only. A CVE in a dev-only dependency is held at Low confidence and tagged (dev dependency).

The CVE bundle​

The bundle (OSV, NVD, CISA KEV and EPSS) lives in ~/.vulkro/data/cves/. Matching is offline by default. VULKRO_CVE_LIVE=1 adds a live lookup at api.osv.dev that sends only ecosystem, name and version (never for transitive packages). For air-gapped machines, apply a signed file with vulkro update --bundle <file>.vkbundle (see bundle format). --max-bundle-age <HOURS> warns on a stale bundle; add --max-bundle-age-fail to exit 2 instead.

Reachability​

Two signals answer "does my code use the vulnerable part?":

  • Call-shape tag (npm and PyPI): a finding is tagged [reachable] when a known call shape for the package (for example _.merge( or yaml.load() appears in your source, else [unreachable]. Unreachable findings drop one severity tier, never removed. --reachable-only drops them; --no-reachability-filter turns the pass off.
  • Call-graph verdict: each finding with known vulnerable symbols gets reachability_verdict (reachable, unreachable or unknown) plus the entry-point call chain. This is a label only. Add --fail-on-reachable-only to stop unreachable CVEs from failing the build. VULKRO_SCA_REACHABLE=0 turns it off.

Both are name-based joins and can miss dynamic dispatch, reflection and aliases. Treat reachable as "look here first", not as proof.

Exploitability​

Every finding carries an exploitability grade in JSON and SARIF:

GradeMeaning
exploitableTainted, unsanitised, user-reachable path to the sink.
likelyStrong signal, one precondition unproven.
theoreticalPattern present, exploitation not shown.

The grade does not change severity. It orders triage, and feeds the "Fix these first" list (--top N).

KEV and EPSS​

SignalEffect
Listed in CISA KEV (actively exploited)Severity raised to Critical, tagged [CISA KEV - actively exploited, added <date>]
EPSS 0.9 or higherSeverity raised to at least High, tagged [EPSS NN%]
EPSS 0.5 to 0.9Tagged only

A dependency matched by a known-malicious-package advisory is reported Critical.

See also: Attack paths, vulkro sbom, vulkro update