Article · Vulnerability scanning

Why npm & pnpm audit miss vulnerabilities

npm audit and pnpm audit are a reasonable first check — but a clean audit is one of the most misread signals in JavaScript security. It doesn’t mean your dependencies are safe; it means one advisory source, reachable at one moment, found nothing in the view of your tree it was handed. Understanding how audit actually works explains exactly where it falls short — and what more complete scanning looks like.

Updated 26 Jul 2026 · by the depproof team

What audit actually does

It helps to know there’s no local analysis happening. When you run npm audit or pnpm audit, the client sends a description of your resolved dependency tree to your configured registry’s audit endpoint, and prints the advisories that come back. That advisory data traces to the GitHub Advisory Database, which curates known vulnerabilities for the npm ecosystem. In other words: audit is a network request to a service, not a scanner with its own database reasoning over your code.

That single design fact explains almost every way audit lets teams down.

The four structural reasons it misses things

  • 1. It’s only as broad as one source. Audit reflects the GitHub Advisory Database for npm. A vulnerability that hasn’t been recorded there yet — or that lives in a different database — won’t appear, no matter how carefully you run it.
  • 2. No network, no results — silently. Because it depends on a reachable audit endpoint, a private registry that doesn’t implement one, an air-gapped runner, or a blocking proxy can turn audit into a command that returns nothing — which reads like “all clear” but means “didn’t actually check.” That failure mode isn’t unique to audit: an empty scan result is ambiguous by nature.
  • 3. It’s npm-ecosystem only. Audit sees your JavaScript dependencies and nothing else. A repo that also ships Java, Go, or containers needs separate tooling — audit gives no signal there.
  • 4. Presence, not reachability — and no inventory. Audit reports that a vulnerable version is present; it can’t tell you whether the vulnerable code path is actually used, and it doesn’t leave you a machine-readable component inventory (an SBOM) to reason about later. You get a console dump, not an artifact.

Why npm audit and pnpm audit disagree

Teams are often unsettled to find npm audit clean while pnpm audit flags issues, or vice versa. Both hit a registry endpoint backed by the same advisory data, so the difference comes from what they ask about: how each resolves and deduplicates the tree, whether devDependencies are included, and the exact state of the advisory data at the moment of the call. Different views of the tree, and different timing, yield different counts. The lesson isn’t “trust the stricter one” — it’s that a single audit number is a fragile measure of dependency risk.

What more complete scanning looks like

None of this makes audit useless — it makes it a floor. A more dependable approach fixes the structural gaps directly:

  • Read the lockfile, not a service. Resolving pnpm-lock.yaml / package-lock.json locally means the scan works behind a private registry, a mirror or a proxy — no audit endpoint required.
  • Check open, aggregated advisory data. OSV pulls from many sources (including GitHub Advisories and OpenSSF malicious-package data) and is built to be queried directly against a lockfile — broader than a single source, and portable rather than proprietary.
  • Produce an inventory. Emitting a CycloneDX SBOM alongside the findings gives you something durable to re-check when the next advisory drops — the difference between a one-off console dump and continuous coverage.

The point isn’t a specific tool — it’s the shape: lockfile-based, open advisory data, full transitive tree, real artifact. That shape removes the network dependency, the single-source blind spot, and the “no inventory” gap in one move.

Frequently asked questions

How does npm audit (and pnpm audit) actually work?

When you run npm audit or pnpm audit, the client sends a description of your resolved dependency tree to your configured registry’s audit endpoint and displays the advisories that come back. That advisory data traces to the GitHub Advisory Database, which curates the npm ecosystem’s known vulnerabilities. The key point is that audit is a network request to a service — it isn’t analyzing your code or maintaining a local vulnerability database.

Does a clean npm/pnpm audit mean my dependencies are safe?

No. A clean audit means one advisory source, reachable at one moment, found nothing for the view of the tree it was given. It can miss vulnerabilities that aren’t in the GitHub Advisory Database yet, return nothing when the audit endpoint is unreachable (a private registry, air-gapped CI, or a proxy), and it says nothing about whether a vulnerable code path is actually used. Treat a clean audit as one signal, not a guarantee.

Why do npm audit and pnpm audit give different results?

Both hit a registry audit endpoint backed by the same advisory data, but they can differ in how they resolve and deduplicate the dependency tree, which dependencies they include (production-only versus including devDependencies), and the exact state of the advisory data at the moment of each call. Different views of the tree, and different timing, produce different result counts — which is why one can look clean while the other flags issues.

What is the difference between npm audit and OSV-based scanning?

npm audit relies on a registry audit endpoint and the GitHub Advisory Database for the npm ecosystem. OSV (osv.dev) is an open, aggregated vulnerability database that pulls from many sources — including GitHub Advisories and OpenSSF malicious-package data — and is designed to be queried by tools directly against a lockfile. Scanning a lockfile against OSV doesn’t need a registry audit endpoint, works offline or self-hosted, and draws on a broader set of advisory sources.

How can I scan dependencies for vulnerabilities more completely?

Use a scanner that reads your lockfile directly (so it works without a registry audit endpoint, offline, or behind a private registry), checks against open aggregated advisory data like OSV, resolves the full transitive tree, and produces a machine-readable inventory (an SBOM) alongside the findings. That combination addresses the network dependency, the single-source coverage gap, and the “no inventory” limitation of the built-in audit commands at once.

Keep reading

General information for engineering teams. depproof is not affiliated with npm, pnpm, GitHub, or Snyk; product names are used nominatively.