Operational guidance, not legal advice. This page distills named public sources (regulator guidance and industry practice). It is not a legal determination, not a notification decision, and not a substitute for your counsel, insurer, or a retained DFIR firm. Verify applicability and current deadlines for your facts and jurisdiction.

How do you detect vulnerable open-source packages?

Updated

Detecting vulnerable open-source packages is software composition analysis (SCA): matching the components you actually ship — direct and transitive — against advisory feeds like OSV, the GitHub Advisory Database, and NVD. A match is not proof of exploitability. This page is not legal advice.

Detecting vulnerable open-source packages, last verified 10 September 2026, against the OSV schema, the GitHub Advisory Database, the National Vulnerability Database (NVD), OWASP software-composition-analysis guidance, and OpenSSF supply-chain materials. It is not legal advice, not a complete SCA program, and not a determination that any specific package in YOUR estate is exploitable.

This is software composition analysis, not YOUR scan

Audience: an engineer, security engineer, or CISO who wants to catch a vulnerable open-source component before it ships. This page is not legal advice. It does not run software composition analysis on YOUR codebase, does not inventory YOUR dependencies, and does not determine that a specific package in YOUR estate is exploitable.

Software composition analysis (SCA) is the practice of identifying every open-source and third-party component a codebase pulls in — directly and transitively — and matching that inventory against vulnerability advisories. A scanner working from a manifest alone only sees the packages that manifest names; a scanner working from a resolved lockfile sees what actually gets installed, several layers deep. That difference is most of what separates a useful SCA result from a misleading one. Last verified 10 September 2026.

  • Guidance versus best practice versus data source: OWASP's Dependency-Check and software-composition-analysis materials and OpenSSF's supply-chain guidance are best practice, not a statute. OSV, the GitHub Advisory Database, and NVD are advisory data sources, not law in themselves; whether a listed CVE creates an obligation for YOU depends on whether a framework control such as ISO/IEC 27001:2022 A.8.8 or SOC 2 TSC CC7.1 applies, which this page does not decide.
  • The what-is-an-SBOM guide on this site is the format and inventory page. The end-of-life-dependencies guide on this site is the unsupported-component page. The how-ShipReadyMetrics-prioritizes-risk guide on this site is the product-method page. A dedicated program-checklist, vulnerability-vs-exploit-vs-risk, CVE-vs-CWE-vs-CVSS, what-is-KEV, how-to-prioritize-vulnerabilities, exploitability-vs-severity, remediation-timeframes, remediation-SLAs, handle-zero-day, prove-remediation, and track-accepted-risk guide either ships alongside this page or is not on this site yet; naming any that are not yet live is not a link.
  • A dedicated what-is-vulnerability-management pillar for this cluster is not linked from this page. Naming it is not a link.

Direct versus transitive — why the lockfile is the difference

A manifest (package.json, pyproject.toml, pom.xml, and equivalents) names the packages a project asked for directly. It does not, by itself, name everything that ends up installed — most of those direct packages bring their own dependencies, which bring their own, often several layers deep. A resolved lockfile is what turns that hidden tree into a list you can actually check. Last verified 10 September 2026. Not legal advice.

Direct vs. transitive dependency exposure (accessible table, not a dependency graph; not YOUR inventory; not legal advice)
Dependency typeHow it enters your buildWhere a CVE surfacesWhat a lockfile changes
Direct dependencyDeclared explicitly in your manifest.An advisory against that exact package name is visible from the manifest alone.Confirms the resolved version actually installed, which the manifest range alone does not.
Transitive dependencyPulled in by a direct dependency's own dependencies, sometimes several layers deep.The vulnerable package never appears in your manifest, so a manifest-only scan can miss it entirely.A resolved lockfile is what makes the transitive package, and its exact version, visible at all.
Declared version range (for example ^2.14.0)A manifest states a range, not the version actually installed.A range can span both a vulnerable release and a fixed one, so the manifest alone cannot say which side of the fix you landed on.The lockfile pins the resolved version. Without it, the honest answer is 'needs a check,' not a verdict.

A worked example: a transitive advisory (illustrative, not YOUR estate)

Log4Shell (CVE-2021-44228), publicly disclosed in December 2021, is a widely documented example of why transitive resolution matters. The vulnerable component, Apache Log4j's log4j-core, was rarely a direct dependency for most affected organizations — it was pulled in transitively through other frameworks and libraries that used it for logging. A scan that only checked a project's own manifest for the literal string log4j-core would have found nothing in many of those codebases, because that name never appeared there; it showed up only once the resolved dependency tree was inspected.

This example illustrates a pattern in how transitive advisories propagate. It is not a claim about any reader's current dependency tree, and it is not a finding about whether any particular codebase was, or still is, affected by CVE-2021-44228 or any other advisory. Whether a given codebase is affected by a specific CVE is a question for that codebase's own resolved lockfile, checked against a current advisory feed — not a question this page answers for you. Last verified 10 September 2026. Not legal advice.

  • Contemporaneous advisories from vendors and from CISA in December 2021 described exposure that propagated across the Java ecosystem through many intermediate libraries — the pattern this example illustrates, not a count of any particular organization's affected systems.
  • The general lesson outlives this one CVE: any ecosystem with deep transitive trees — npm, Maven, PyPI, NuGet, and others — can carry a vulnerable package several layers below anything a manifest names.
  • A single shared library CVE like this one can appear once per repository that resolves it transitively, which is why counting per-occurrence rather than per-distinct-advisory can overstate how many separate problems exist.

Presence is not exploitability — the reachability caveat

A component appearing in your dependency tree, even at a vulnerable version, does not by itself mean the vulnerable code path is reachable from your application. Reachability analysis asks whether your code actually calls the vulnerable function, class, or code path — not merely whether the package is installed. A vulnerable package that is present but never invoked carries materially different risk from the same package sitting on your primary request path. Last verified 10 September 2026. Not legal advice.

This distinction matters because treating every vulnerable-version match as equally urgent inflates the queue past what any team can work through. Presence is the finding; reachability, exposure, and exploitation evidence — the KEV and EPSS material named elsewhere in this cluster — are what turn a finding into a priority. Absence of a visible call site is not a guarantee of safety either: reachability analysis has its own blind spots, including dynamic dispatch, reflection, and deserialization paths that static analysis can miss. Treat a 'not reachable' result as a downgrade signal, not a dismissal.

  • Present, reachable, and confirmed under active exploitation: treat as the highest-priority combination available.
  • Present, but not reachable by static analysis: a lower-likelihood finding, not a zero — reflection and dynamic loading can still reach code static analysis does not trace.
  • Present only in a dev-only or test-only dependency path: a materially different exposure profile than the same package on a production runtime path, and worth recording as such rather than discarding.

Authoritative advisory feeds versus scanner heuristics

Not every 'vulnerability found' message rests on the same kind of evidence. Some advisory sources publish a structured, reviewed record tied to a specific package name and version range. Some scanner output is a heuristic match — a filename pattern, an embedded version string, or a fuzzy signature — that can be wrong in either direction. Reading a scanner's severity label as equivalent to a reviewed advisory is a common misread. Last verified 10 September 2026. Not legal advice.

Advisory feed vs. scanner heuristic (not a ranking of tools; not legal advice)
SourceWhat it isKind of textWhere it can be wrong
OSV (OSV.dev / the OSV schema)A structured, open, machine-readable vulnerability database and schema aggregating advisories across ecosystems including npm, PyPI, Go, crates.io, and more, each entry naming affected package and version ranges.Aggregated advisory data published under the OSV schema. Not a statute.Coverage depends on what each upstream ecosystem publishes into it; a very new advisory may lag its first appearance elsewhere.
GitHub Advisory DatabaseGitHub's curated database of security advisories, including advisories reported directly to GitHub and advisories synced from NVD and other sources, powering Dependabot alerts.Curated advisory database. Not a statute.Advisory review takes time; a same-day disclosure elsewhere may not yet carry a GHSA identifier.
NVD (National Vulnerability Database)The U.S. NIST-run repository that enriches CVE records with a CVSS score, CWE classification, and affected-product data.Authoritative U.S. government advisory enrichment. Not a statute in itself.NVD has publicly experienced analysis backlogs; a CVE can exist before its NVD enrichment is complete.
Scanner heuristic matchA tool infers a vulnerable version from a file hash, an embedded version string, or a dependency-tree parse, rather than from a structured advisory lookup.Vendor tooling output. Not an advisory source in itself.Can false-positive on a patched fork or vendored copy, and can false-negative on a renamed or repackaged copy of the vulnerable code.

Counting honestly: distinct advisories, not per-occurrence noise

A single shared-library advisory can surface once per repository, once per branch, or once per scanner that happens to check it — which means a raw finding count can multiply one real problem into dozens of rows without any new risk being created. Reporting 'we have 40 open vulnerability findings' without saying how many distinct CVEs that represents, and across how many repositories, invites the wrong read of how big the backlog actually is. Last verified 10 September 2026. Not legal advice.

The corrective is to count two numbers, not one: the number of distinct advisories, and the number of places each one appears. Forty findings that resolve to three distinct CVEs across many repositories is a very different backlog from forty distinct CVEs, and only reporting the first number as if it were the second overstates the exposure either way.

  • Report distinct-CVE counts alongside occurrence counts, not instead of them — both numbers answer a real question.
  • When comparing two teams' or two periods' backlogs, normalize by estate size (repositories, services, or hosts) rather than comparing raw counts, since a larger estate will always show more raw findings for the same underlying rate.
  • A scanner reporting zero for a package it never actually resolved transitively is not evidence the package is absent — see the reachability and lockfile sections above.

What to do now

The list below is operational practice, not a program run for you. It does not determine that any package in YOUR estate is affected or exploitable. Last verified 10 September 2026. Not legal advice.

  • Generate or request a current SBOM — see the SBOM guide on this site — so 'what do we actually ship' is answered from data rather than memory.
  • Match declared and transitive components against a structured feed such as OSV, the GitHub Advisory Database, or NVD, rather than relying on a single scanner's built-in list alone.
  • Where a manifest declares a version range rather than a pin, treat the result as 'needs a check' until a resolved lockfile confirms the version actually installed.
  • Layer reachability, exploitation evidence, and exploitation probability on top of a raw advisory match before deciding what to fix first, rather than sorting by severity alone.
  • Do not treat a clean scan as proof of absence: it only covers what was scanned, what the lockfile resolved, and what the feeds queried that day actually listed.
  • Retire end-of-life components on their own timeline even absent a current CVE; an unsupported component is an accepted risk whether or not a specific advisory has landed yet.

Where this shows up in ShipReady Metrics

If you already have a session: signed-in app → Security → Findings ingests dependency findings from GitHub Dependabot alerts and code-scanning results when those sources are connected, alongside first-party SAST and DAST findings. Cross-source dedup collapses the same advisory seen by more than one connected source, so a distinct CVE is not counted once per repository and once per scanner tool.

Signed-in app → Security → Blast radius answers 'which repositories declare or install a named package' from npm lockfiles (package-lock.json, npm-shrinkwrap.json) resolved transitively when the GitHub scan fetched them. Yarn, pnpm, NuGet, and PyPI dependencies, and any npm repository without a readable lockfile, remain what the manifest declares — a version range cannot be judged against a bound from a manifest alone, and a package pulled in only transitively through one of those other ecosystems will not appear in that view. That limit is disclosed on the blast-radius page itself, not only here.

This product does not run reachability analysis, does not determine that a specific advisory is exploitable in YOUR deployment, and does not patch dependencies on YOUR behalf. A named human still owns the remediation decision. This page does not document a public demo URL.

Primary sources (last verified 10 September 2026)

Every claim on this page is taken from one of these. If a later revision of a source changes the rule, the date above is how you can see we have not re-checked yet.

The OSV schema and OSV.dev are an open, aggregated vulnerability database and schema, not a statute. The GitHub Advisory Database is GitHub's curated advisory database, not a statute. NVD is the U.S. NIST-run vulnerability enrichment repository, not a statute in itself. OWASP's Dependency-Check and software-composition-analysis materials are best practice, not law. OpenSSF's supply-chain-security materials are best practice, not law. CVE-2021-44228 (Log4Shell) advisories from CISA and affected vendors in December 2021 are the historical, public source for the worked example above; that example is illustrative and is not a finding about any reader's estate. These are not a complete world list. Not legal advice.

The what-is-an-SBOM guide on this site is the format and inventory page. The end-of-life-dependencies guide on this site is the unsupported-component page. The how-ShipReadyMetrics-prioritizes-risk guide on this site is the product-method page. The vulnerability-management glossary entry on this site is the education page under glossary. The SBOM glossary entry and the SBOM-and-blast-radius learn guide on this site are live.

Frequently asked questions

Is this legal advice?

No. It is a vendor-neutral explainer on software composition analysis, distilled from the OSV schema, the GitHub Advisory Database, NVD, OWASP SCA guidance, and OpenSSF materials. Whether a specific package in YOUR estate is vulnerable, exploitable, or creates an obligation under a framework you have adopted is a question for your own SCA process and, where relevant, counsel. This page is not legal advice.

Does a scanner that reports zero findings mean we are not affected?

No. A clean scan only covers what was actually scanned: a manifest-only tool that never resolved the lockfile can report zero findings while a transitive dependency several layers down is vulnerable. A zero from a scan that never ran against a resolved lockfile is a blind spot, not a clean result. Verify what the scan actually resolved before treating a zero as reassurance.

Does presence in our dependency tree mean a package is exploitable?

No. Presence at a vulnerable version is the finding; whether the vulnerable code path is reachable from your application is a separate question. A package that is present but never invoked carries materially different risk from the same package on a production request path. This page does not run that reachability check for YOUR codebase.

Was every organization using Log4j affected by Log4Shell?

This page does not make that determination. CVE-2021-44228 is used here as a widely documented historical example of transitive-dependency exposure, not as a claim about any reader's estate. Whether a given codebase was, or still is, affected by that CVE or any other is a question for that codebase's own resolved lockfile against a current advisory feed.

Does ShipReady Metrics run software composition analysis or reachability analysis for us?

The signed-in app ingests dependency findings from connected sources such as GitHub Dependabot and code scanning, deduplicates across sources, and answers npm-lockfile-scoped blast-radius questions when a lockfile was fetched. It does not run reachability analysis, does not determine that a specific advisory is exploitable in YOUR deployment, and does not patch dependencies on YOUR behalf. A named human still owns the remediation decision.

Is a high finding count the same as a large number of distinct problems?

Not necessarily. The same shared-library advisory can appear once per repository or once per scanner that checks it, so a raw finding count can multiply one real advisory into many rows. Look at the distinct-CVE count alongside the occurrence count, and normalize by estate size before comparing backlogs across teams or time periods.

Published by ShipReady Metrics, an evidence-based technology and compliance intelligence platform. This guide is educational and vendor-neutral.