tty/0·uid=audit gid=audit
docs.reachability()

most findings don't deserve your attention

scanners are judged by what they find, so they find everything. the result is the familiar wall: 200 findings, of which maybe five change what you do this week. virgil's job is deciding which five — this page explains the two mechanisms that do most of that work.

## reachability: is the vulnerable code even yours to worry about?

dependency scanners flag every CVE in every package in your lockfile. but a lockfile entry is not exposure — transitive dependencies, dev tooling, and optional extras pile up packages your code never touches. virgil cross-references each dependency CVE against your actual source: does any file import (require, use) the vulnerable package?

  • +reachable — your code imports the package: the CVE keeps its severity and its place in the queue
  • +unreachable — nothing imports it: the CVE drops one severity rung and hides by default (visible with one click, never deleted)

this works across five language families — python (requirements, poetry, pipfile), javascript/typescript (package.json + lockfiles), go (go.mod), ruby (gemfile), java/kotlin (maven, gradle). unreachable is a demotion, not a verdict of safe — which is exactly why it's reversible and logged.

## clusters: count problems, not symptoms

the second mechanism attacks duplication. when semgrep reports sql injection at 47 call sites, the useful unit isn't the call site — it's the one raw-query helper they all flow through. virgil groups findings that share a root cause into a single cluster whose headline points at the shared code:

#02 [ HIGH ]  SQL injection via raw query helper  ×12
      12 callsites share src/db/query.py — fix the helper, not callsites.

one fix, twelve findings resolved. the cluster keeps every member finding as evidence, so nothing is hidden — it's the same information, aggregated at the altitude you actually fix things.

## what survives gets ranked

after demotion and clustering, the queue is short enough to rank honestly: severity, how much of the codebase a cluster touches, whether the CVE is in CISA's known-exploited-vulnerabilities catalog (a KEV entry means someone is using it in the wild — it outranks a theoretical critical). each item carries a one-line rationale. with no model in the loop, a deterministic fallback produces the same queue shape — ranking is a product feature, not an llm trick.

## the numbers you see

 CRIT  HIGH  MED   LOW   INFO  KEV  unreach
   2     7    14    6     3     1     19

that unreach 19 is the point: nineteen dependency CVEs that would have been rows in another tool's report, demoted because your code never touches the vulnerable packages. the two criticals are what your week is for.

see the whole pipeline on how it works, or run it on your repo — 3 free audits, no card.