Skip to content

feat: add npm advisory API as supplemental vulnerability source - #1056

Merged
sonukapoor merged 8 commits into
mainfrom
feature/issue-1054-npm-advisory-secondary-source
Aug 28, 2026
Merged

feat: add npm advisory API as supplemental vulnerability source#1056
sonukapoor merged 8 commits into
mainfrom
feature/issue-1054-npm-advisory-secondary-source

Conversation

@sonukapoor

Copy link
Copy Markdown
Collaborator

After the OSV batch pass, CVE Lite CLI now queries the npm registry advisory API (POST https://registry.npmjs.org/-/npm/v1/security/advisories/bulk) for all npm packages in the scan. This is the same API npm audit uses internally and maintains its own package-to-CVE mappings independently of OSV, so it closes the timing gap where a CVE exists in OSV but has no npm ecosystem mapping yet.

Results are deduplicated against OSV findings by vuln ID before surfacing, so a package already covered by OSV never appears twice. The npm advisory pass is cached in a new npmAdvisoryEntries section (cache bumped to v5; v4 loads cleanly), skips entirely in offline mode, and is non-fatal - any network error leaves OSV results untouched.

New src/advisory/npm-advisory-source.ts with 7 unit tests. Cache and scanner integration covered by 5 integration tests. 1519/1519 passing.

Closes #1054

Add a supplemental npm advisory pass in scanPackages that runs after the
OSV scan. Packages in the npm ecosystem that OSV found nothing for are
checked against the npm advisory bulk API (queryNpmAdvisoryGaps). Results
are stored in cache.npmAdvisoryEntries (keyed by "npm:name@version") so
repeat scans serve from cache without hitting the network.

npm-sourced vuln objects are pre-populated in vulnMap before the OSV
detail-fetch loop, so the loop's uncachedIds guard skips them and avoids
unnecessary getVuln calls. The gap-filler is skipped entirely in offline
mode via the existing !offline guard.
- npm-advisory-source: add null/non-object body guard after response.json()
  so a proxy returning HTTP 200 with body null does not crash the scan
- scanner: switch zero-match detection from package name to name@version
  key so foo@1.0.0 (no OSV hits) gets its gap filled even when foo@2.0.0
  has OSV results in the same scan
- scanner-npm-advisory.test: replace placeholder expect(true) with a real
  assertion that queryNpmAdvisoryGaps is never called when offline is true
… results

Previously the npm advisory secondary source only queried packages where
OSV returned zero matches. A package with some CVEs in OSV could still have
additional advisories in npm's DB that OSV has not yet mapped - those were
missed entirely.

Now the pass queries all npm packages and deduplicates at merge time: the
cache entry always stores what npm advisory returned (full list), but only
vulns whose ID is not already in the OSV result set are added to findings.
This closes the gap for packages partially covered by OSV while preserving
correct cache semantics for future scans.

Updated tests: replaced the "does NOT call for OSV-covered packages" test
with a dedup correctness test, and added a new test that verifies npm
advisory supplements OSV when the two sources cover different vulns for the
same package.
@sonukapoor
sonukapoor merged commit 8a55738 into main Aug 28, 2026
6 checks passed
@sonukapoor
sonukapoor deleted the feature/issue-1054-npm-advisory-secondary-source branch August 28, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: npm advisory API as supplemental source for OSV zero-match packages

1 participant