Runs dead-dependency analysis across JS, Python, and Rust projects using ecosystem-native static tools (`depcheck`/`knip` for JS, `vulture` for Python, `cargo-machete` for Rust), then cross-references the unused-dependency list against SCA findings to downrank vulns in code that is never loaded. Use when SCA output (from `osv-scanner`, `snyk-test`, or `npm-pip-maven-audit`) is too noisy to triage and the team needs to separate unreachable CVEs from exploitable ones before sprint planning; sibling cve-exploitability-triage ranks by EPSS/KEV exploitation signal, not code reachability.
79
99%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Static vulnerability scanners report a CVE for every declared dependency that
matches a vulnerable version, regardless of whether the vulnerable code is ever
executed. A critical-severity finding in a test-only helper that your production
build tree never reaches is a different risk level than the same CVE in a
hot-path dependency. This skill operationalizes a reachability heuristic:
run an ecosystem-native dead-dependency tool, produce an unused-deps.txt
artifact, and feed that list into your SCA prioritization step so it can
assign reachable: false and route affected findings to Fix-Backlog instead
of Fix-Now.
The approach is static-analysis heuristic only. A dependency flagged unused by these tools is a strong signal to deprioritize its CVEs, not a guarantee that the vulnerable code is unreachable at runtime. Treat it accordingly.
reachable field is
populated.Run SCA first and save the findings JSON - this skill annotates existing
findings, it does not replace them. See osv-scanner (or snyk-test /
npm-pip-maven-audit) for full setup:
osv-scanner scan -r . --format json --output osv.jsonRun the ecosystem-native dead-dependency tool for your stack, then extract
the unused names into unused-deps.txt. Full config, flags, exit codes, and
suppression per tool:
references/dead-dependency-tools.md:
# JS/TS - knip (preferred; depcheck was archived June 2025)
npx knip --reporter json | jq -r '.dependencies[].name' > unused-deps.txt
# Python - vulture; --min-confidence 90 targets unused imports
vulture src/ --min-confidence 90 > vulture-report.txt
# Rust - cargo-machete; --with-metadata catches renamed/feature-gated crates
cargo machete 2>&1 | grep "unused dependency" | awk '{print $NF}' > unused-deps.txtKeep production and dev unused-dep lists separate: dev deps with CVEs can still reach production in bundled builds.
Cross-reference unused-deps.txt against the SCA JSON, setting
reachable: false on every finding whose package is unused (script below).
Verify: assert unused-deps.txt is non-empty and every finding in the
annotated JSON carries a populated reachable field before handoff. If the
file is empty or a finding lacks the field, re-run the dead-dependency tool
(a silent tool failure or the wrong workspace root is the usual cause) and
re-annotate before proceeding.
Pass the annotated JSON to your SCA prioritization step; reachable: false
routes to Fix-Backlog unless the CVE is in the CISA KEV catalog.
Wire steps 2-4 into CI so the annotated artifact feeds the prioritization job on every run, and still schedule each unused package for cleanup.
Once you have an unused-deps.txt for your ecosystem, annotate the SCA JSON
output before passing it to your SCA prioritization step:
import json
with open("osv.json") as f:
findings = json.load(f)
with open("unused-deps.txt") as f:
unused = {line.strip() for line in f}
for finding in findings.get("results", []):
pkg = finding.get("package", {}).get("name", "")
finding["reachable"] = pkg not in unused
with open("osv-annotated.json", "w") as f:
json.dump(findings, f, indent=2)Pass osv-annotated.json to your SCA prioritization step. Per the priority
logic, findings with reachable: false route to Fix-Backlog regardless of
severity, unless they are in the CISA KEV catalog.
jobs:
reachability:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: JS unused deps (knip)
run: npx knip --reporter json | jq -r '.dependencies[].name' > unused-deps.txt
- name: Annotate OSV output
run: python3 ci/annotate-reachability.py osv.json unused-deps.txt
- uses: actions/upload-artifact@v4
with:
name: osv-annotated
path: osv-annotated.jsonThe annotated artifact is then consumed by the prioritization job.
A team's OSV scan of a Next.js service returns 60 CVEs - too many to patch in one
sprint. They run the JS dead-dependency tool (step 2), which flags 12 of the 80
declared dependencies as unused, including moment (CVE-2022-31129, CVSS 7.5). The cross-reference script sets
reachable: false on the moment finding because moment appears in
unused-deps.txt. Prioritization routes that CVE to Fix-Backlog instead of
Fix-This-Sprint, and the team removes moment in the next dependency-cleanup PR,
eliminating both the CVE and the unused weight in one change.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Skip reachability; sort SCA output by CVSS only | Teams spend sprints patching vulns in unused code while exploitable issues sit in Fix-Backlog | Run the cross-reference step before triage |
Treat reachable: false as safe | Static heuristic; dynamic imports and plugin systems can load code at runtime | Use as deprioritization signal only; still schedule Fix-Backlog cleanup |
| Run vulture at default confidence (60%) | Reports unused functions/variables alongside imports; noisy for CVE mapping | Use --min-confidence 90 to target imports specifically |
| Use depcheck on new JS projects | Archived June 2025; per github.com/depcheck/depcheck, maintainers recommend knip | Switch to knip for new setups |
Skip --with-metadata in Rust monorepos | Renamed crates not detected; false "used" verdicts | Always pass --with-metadata in CI |
| Ignore devDependencies entirely | Dev deps with CVEs can reach production in bundled builds | Separate prod/dev lists; confirm --omit=dev in audit scope |
require(variable)
in JS, importlib.import_module in Python) and compile-time proc macros in
Rust can defeat detection, producing false "unused" verdicts.osv-scanner,
snyk-test,
npm-pip-maven-audit - SCA tools whose
output this skill annotates