how to check if a CVE affects your dependencies
A focused skill for answering 'given CVE-X, is MY stack affected': scanning your lockfiles with osv-scanner and ecosystem tools, matching the CVE to flagged entries, and confirming reachability. Use when a specific CVE is named and you need a yes-or-no for your repos. Triggers: 'am I affected by CVE', 'check my dependencies for CVE', 'is CVE in my lockfile'. Not for: broad audits of all transitive deps, severity theory, writing advisories.
how to check if a CVE affects your dependencies
TL;DR
Dont eyeball version ranges by hand. Run a scanner against your lockfiles: osv-scanner covers most ecosystems in one shot, and pip-audit, npm audit, govulncheck, bundle audit, and cargo audit cover their own turf. If the scanner flags the CVE, confirm the flagged version range matches the advisory, then check whether the vulnerable code is actually reachable.
how to check if a CVE affects your dependenciesUse this when
- Someone names a specific CVE and asks "are we affected"
- A security advisory lists a CVE for a library you might use
- You want a yes-or-no answer per repo, not a full audit report
- You are verifying a scanner finding before patching
Not for this skill when
- You want a standing audit of every transitive dependency (different workflow)
- You are triaging a brand-new CVE with no scanner data yet (use the triage skill)
- The question is about severity ranking, not affected-or-not
Steps
1. Find every lockfile in scope
You can only answer for repos you actually scan. List the lockfiles across the repos that matter: package-lock.json, poetry.lock, requirements with hashes, go.mod plus go.sum, Gemfile.lock, Cargo.lock.
find ~/workspace -maxdepth 3 -name "package-lock.json" -o -maxdepth 3 -name "poetry.lock" -o -maxdepth 3 -name "go.mod" -o -maxdepth 3 -name "Gemfile.lock" -o -maxdepth 3 -name "Cargo.lock"Expected: a list of lockfile paths. Every repo you skip is a repo you cant answer for; note the gaps.
2. Run osv-scanner across them
osv-scanner reads the lockfiles directly and matches against the OSV database, which aggregates CVE data across ecosystems. One tool, most languages.
osv-scanner --recursive --skip-git ./Expected: a table of findings with CVE IDs, affected packages, and fixed versions, or a clean result. Save the output; you will match your CVE against it in step 4.
3. Run the ecosystem-native scanner for your main language
Native tools understand their ecosystem's quirks (vendoring, groups, build tags) better than any generic scanner. Run the one that matches your stack.
npm audit --omit=devExpected: npm's own advisory list for production deps. Equivalents: pip-audit for Python, govulncheck ./... for Go (this one also checks reachability), bundle audit check for Ruby, cargo audit for Rust. If the native tool and osv-scanner disagree, trust the native tool for its own ecosystem and investigate the gap.
4. Match your CVE against the findings
Search the scanner output for the exact CVE ID. Confirm the flagged package version falls inside the advisory's affected range and below the fixed version; scanners occasionally flag on overly broad ranges.
osv-scanner --lockfile=package-lock.json --format json | python3 -c "import json,sys; d=json.load(sys.stdin); rs=d.get('results',[]); print([ (r['packageSource']['path'], v['id']) for r in rs for v in r.get('vulnerabilities',[]) if v['id']=='CVE-2026-12345'])"Expected: either matches pairing the CVE with specific lockfiles, or an empty list meaning not flagged. Empty plus a manual version check against the advisory range is a solid "not affected".
5. Confirm reachability before you patch
Flagged is not the same as exploitable. Check whether your code actually imports and calls the vulnerable package, and whether the vulnerable feature is enabled. Go's govulncheck does this automatically; for other ecosystems, grep for the import and the vulnerable API.
grep -rn "from [package] import" src/ | head; grep -rn "require('[package]')" src/ | headExpected: import lines, or nothing. Reachable means patch on the normal schedule for the severity; unreachable means schedule it with everything else and note why.
Variant: am I affected by CVE-2026-XXXX
The one-liner version: run osv-scanner on the repo, grep the output for the CVE ID. If it appears, check reachability; if not, spot-check the version range in the advisory and move on. Five minutes, defensible answer.
Variant: check my lockfile for a specific vulnerability
Same as above but starting from the lockfile instead of the repo: osv-scanner --lockfile=[path] then match. Useful when someone hands you a lockfile from a service you dont own.
Variant: is my docker image affected by this CVE
Dependencies live in image layers too. Scan the image itself (trivy image [image]:[tag] or grype [image]:[tag]) and match the CVE there; the app lockfile wont show OS-package CVEs.
Why this happens
Version ranges in advisories are written for every consumer of a library, and humans are bad at comparing semver ranges across nested transitive trees. Scanners exist because "do we use libfoo between versions 2.1 and 2.4.7" is a database lookup, not a judgment call. The judgment call comes after: reachability.
Edge cases and pitfalls
- No lockfile committed: without one, the scanner guesses from manifests and the answer is unreliable; commit the lockfile first.
- Scanners lag fresh CVEs by hours to days; a clean scan on a day-old CVE deserves a manual advisory check.
- Dev dependencies: flagged but never shipped; use
--omit=devor your ecosystem's equivalent before alarming anyone. - Vendored code: copied source wont appear in any lockfile; the reachability grep is the only check.
- Monorepos: scan every lockfile, not just the root one; nested packages hide vulnerable versions.
- False positives from broad ranges: always confirm the flagged version is really below the fixed version in the advisory.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_5lLAKJbGwjcV4A5kBzh4jQ
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.