Cut CVE noise with reachability

Measure how many of your CVEs can't be reached from your code, across every repository, with no setup.

Most CVEs in a dependency tree sit in code your application never calls. Reachability analysis finds those and marks them unreachable, so your team works on the rest. Socket has three tiers:

TierWhat it looks atSetupReduction Socket cites
Dependency reachabilityWhether each transitive package is imported by anything at allNone, every scanUp to 35%
PrecomputedCall paths from your direct dependencies down to vulnerable transitive packagesNone, every scanUp to 80% of transitive CVEs
Full applicationCall paths from your own code, through direct and transitive dependenciesAdd --reach to a scanUp to 90%

Results vary by codebase, which is why the POC measures yours. It runs in two steps: precomputed reachability across every repository for the headline number (this page), then full application reachability on one or two apps for depth.

Before you start: a baseline for your repositories (Connect your repositories). Precomputed results are already in it.

1. Agree the bar

Before you look at any numbers, agree with Security what counts as a pass, and which of the two figures in step 2 it applies to. Bars teams have set range from 60% to 70% noise reduction. Writing it down first keeps the result from being argued after the fact.

2. Get the headline number

  1. Open Alerts in the dashboard. It covers the default branch of every repository.
  2. Filter Category to Vulnerability. Write down the total.
  3. Set the CVE Reachability filter to Unreachable. Write down the count.
  4. Set the CVE Reachability filter to Direct dependency. Write down the count.
  5. Work out both figures:
    • Overall noise reduction: unreachable divided by the total, times 100.
    • Transitive noise reduction: unreachable divided by (total minus direct dependency), times 100.
🚧

Direct-dependency CVEs pull the overall figure down

Precomputed analysis doesn't cover CVEs in your direct dependencies. They stay in the total but can never count as unreachable, so if they're a large share of your CVEs, the overall figure will be low. In one test app, 35 of 49 CVEs were in direct dependencies: overall noise reduction was 6%, transitive was 21%, and full application analysis on the same app reached 41%. Report the transitive figure for the estate, and use full application reachability for the overall figure on the apps you pick.

To turn it into hours, fill one row per business unit or repository group:

Total CVEsDirect dependencyUnreachableOverall %Transitive %Hours to fix one CVEHours saved

Hours saved is the unreachable count times the hours to fix one CVE. Use your team's own figure for the hours; if you don't have one, state the assumption you used.

Read the verdicts

Dashboard labelAPI valueMeaningWhat to do
ReachablereachableA call path from your code may trigger the CVE (full application only)Fix it
Potentially reachablemaybe_reachableA call path through your dependencies may trigger it; use from your own code is unknown (precomputed only)Keep in scope; full application analysis settles it
UnreachableunreachableNo call path triggers the CVEDeprioritize
Pending precomputationpendingQueued for analysis, usually minutesRun a new scan; existing scans don't update
Not yet supportedmissing_supportSocket hasn't yet mapped the vulnerable functionsCheck again later
Direct dependencydirect_dependencyThe CVE is in a direct dependency, which precomputed analysis can't coverRun full application analysis
Not determinableundeterminable_reachabilityUsually a CLI or binary not meant to be called from codeJudge it by hand
UnknownunknownThe full application scan hit a problem, often missing private dependenciesInstall all dependencies and rescan
ErrorerrorAnalysis failedCheck the scan logs, or contact Socket

Known limits

  • Private packages hide edges. Precomputed analysis can't see inside a private package, so a vulnerable public package reached only through one can be marked unreachable. Use full application analysis on repositories that lean on internal packages.
  • Python needs a lock file. With requirements.txt, Socket can't tell direct from transitive dependencies, so precomputed analysis has nothing to work with. Commit uv.lock or poetry.lock.
  • Every package manager needs a lockfile for a complete tree. See the troubleshooting table in Connect your repositories.

Verify

  • Vulnerability alerts show a reachability verdict with no extra setup
  • The CVE Reachability filter narrows the list
  • Total, direct dependency and unreachable counts recorded, and both figures worked out
  • Every verdict you see maps to a row in the table above

Automate it

Count the verdicts on one scan. The scan ID is the last part of the scan's report URL, after /sbom/. SOCKET_CLI_API_TOKEN is the variable the Socket CLI reads, so one export covers both the CLI and these calls.

export SOCKET_CLI_API_TOKEN=...
SCAN_ID=your-scan-id
curl -s -H "Authorization: Bearer $SOCKET_CLI_API_TOKEN" \
  "https://api.socket.dev/v0/orgs/your-org/full-scans/$SCAN_ID" \
  | jq -r '.alerts[]? | select(.type | test("CVE|cve"))
           | .reachability.head.results[0].type // "none"' \
  | sort | uniq -c

The verdict is a top-level reachability field on each alert, not under props. CVE alert types are tiered (criticalCVE, cve, mediumCVE, mildCVE), so match on CVE|cve rather than one name.

Next

Full application reachability on one or two apps, then Fix what matters and Patch what you can't upgrade.

Reference


Did this page help you?