Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Report views

The same findings can be reshaped with -f <view> to answer different questions. The fleet-scale views are what single-repo tooling cannot give you.

impact — which fix clears the most repos?

Ranks advisories by how many of your crates they hit.

Repos  Severity      Advisory            Affected                  Title
2      medium 6.2    RUSTSEC-2020-0071   payments-api, scheduler   Potential segfault in time
1      critical 9.8  RUSTSEC-2021-0003   ingest-worker             SmallVec::insert_many overflow
1      critical 9.8  RUSTSEC-2021-0097   ls-replacement            SM2 decryption buffer overflow

The lead row is a medium, not a critical: the time segfault is the one advisory present in two repos, so a single bump clears both. That ordering is the question single-repo tooling cannot answer.

blast — direct vs transitive

Keeps the impact ranking but splits each advisory’s reach into direct vs transitive repos and adds a fix-path hint, because how you fix it depends on the split.

Repos  Direct  Transitive  Fix       Severity      Advisory            Title
2      1       1           mixed     unknown       RUSTSEC-2025-0004   ssl select_next_proto UAF
1      1       0           manifest  critical 9.8  RUSTSEC-2021-0003   SmallVec::insert_many overflow
1      0       1           upstream  medium 6.2    RUSTSEC-2020-0071   Potential segfault in time

An advisory hitting its repos transitively can’t be fixed by editing those repos’ manifests — you need an upstream bump or a dependency override (upstream); a direct one can (manifest). A corpus study of the Go ecosystem found ~3 in 4 vulnerable-dependency exposures are transitive, so a plain affected-repo count hides the fix strategy.

packages — your biggest fleet liability

Rolls the rows up to the dependency. One package often carries many advisories across many repos, and a single bump clears them all.

Repos  Direct  Transitive  Advisories  Severity  Fix       Package
3      0       3           2           medium    upstream  time
2      1       1           7           unknown   mixed     openssl
1      1       0           1           critical  manifest  smallvec

Here a single openssl bump clears seven advisories — a rollup the per-advisory views can’t show. (packages-json emits the same data as JSON.)

fix-first — what do I patch first?

Severity-dominant: actively-exploited (KEV) findings lead, then strict severity bands, and only within a band does blast radius break the tie. The opposite trade-off from impact, which floats a wide-but-informational warning to the top.

remediation — the fix queue

Where fix-first ranks which advisory, this prints what to do about it: the concrete dependency bump. Each row is batched, so a single bump tokio 1.0 → 1.38 clears every advisory that one upgrade resolves across every repo, and breaking (semver-major) jumps are flagged so low-churn fixes go first. Advisories with no published fix are called out honestly (no fix: …). With static reachability, soundly-unreachable advisories drop to an informational tail. (remediation-json emits the queue as JSON.)

Prioritize by real-world risk

--enrich annotates each finding with CISA KEV (actively exploited) and FIRST EPSS (exploit probability), re-ranks them into an action queue, and adds a Risk column:

Severity      Risk      Advisory            Fix                       Title
critical 9.8  epss 88%  RUSTSEC-2021-0097   openssl-src → 111.16.0    SM2 decryption buffer overflow
high 7.5      epss 14%  RUSTSEC-2022-0013   regex 1.5.4 → 1.5.5       regex repetition DoS
critical 9.8  epss 2%   RUSTSEC-2021-0003   smallvec 1.6.0 → 0.6.14   SmallVec::insert_many overflow

The two critical 9.8s are tied by CVSS, but EPSS breaks the tie. Gate with --fail-on-kev or --min-epss 0.5; both feeds can be supplied offline via --kev-file / --epss-file.

Provenance: --why

Every finding shows whether the flagged package is a direct or transitive dependency and the chain that pulls it in. --why <crate> asks that across the whole fleet at once:

$ fleetreach scan --why serde
cli-tools — serde 1.0.228 (direct):
  ripgrep → serde
file-finder — serde 1.0.228 (transitive):
  fd-find → globset → bstr → serde

Tracking drift over time

fleetreach diff <baseline.json> <current.json> compares two saved reports and splits findings into new, fixed, and still-open — the question a single scan can’t answer: did this branch make the fleet better or worse? It is pure (no scanning or network), so it drops into CI as a cheap gate.