Docs

Reading scan results

A successful build does not mean an image has zero reported vulnerabilities. Here is exactly what the numbers mean.

What gets published

  • Grype scans every production image and publishes raw JSON and SARIF results. SARIF is uploaded to the repository's Security tab.
  • Findings are informational. There is no global severity threshold that blocks publication — a CVE with no available fix should not stop a security update to everything else in the image.
  • Dev images are excluded from the dashboard. Their larger toolchain surface is not representative of the production image.

Raw vs effective counts

The catalog shows two numbers. Raw is what the scanner reported. Effective is what remains after applying OpenVEX statements, which can mark a finding not_affected or fixed with a stated justification.

Both are shown deliberately. A single "0 CVEs" headline hides whether it was achieved by patching or by suppression.

Why some advisories are withheld

These images are built from Wolfi packages, so their apk database identifies them as a Wolfi system and the scanner looks up every installed package name in the distro advisory feed — including the packages we build. That feed records fixes against its own rebuild counter:

installed   gitleaks 8.30.1-r0     our first build of 8.30.1
"fixed in"  gitleaks 8.30.1-r13    their fourteenth build of 8.30.1

r0 is lower than r13, so we are reported as unpatched. But -rN is a per-distro build counter, not a patch level — both start at zero and they count different distributions’ build events. Comparing them across distributions is not a meaningful operation.

Each such finding is resolved on evidence, never by blanket suppression:

  • Counted — the vulnerable component is genuinely in the image: the scanner matched the module, jar, gem or crate itself, or the same advisory also matched real binary contents.
  • Withheld — our own package, nothing corroborating in the contents, and the fix is a same-version rebuild. A rebuild at the same upstream version cannot patch the application’s own source, so the fix lives in a dependency or the compiler — which our from-source rebuild already picks up.
  • Needs review — our own package, uncorroborated, but the fix requires a genuinely newer upstream version. That usually means we are behind. Never withheld, and flagged on the image page.

Nothing is deleted. Withheld counts are shown next to the totals so the exclusion can be audited, and a finding that later gains corroboration moves back into the count on its own.

For why two scanners can report different totals for the same image, and how to triage an individual finding, see Why two scanners disagree.

Unscored advisories

Some findings show a severity of Unknown. That is not a gap in our reporting — it is how the source feed publishes them. The Go vulnerability database assigns no CVSS score, so every Go advisory (GO-YYYY-NNNN) arrives unscored.

They are counted in the totals like any other finding. Summing only critical/high/medium/low would report an image carrying them as clean, which is the one thing these numbers must never do.

Suppressions cannot quietly rot

Anything can be suppressed once. The check that matters is whether a suppression is still true, so every scan reconciles VEX statements against fresh results and flags two kinds of drift:

  • Stale — the suppressed CVE is no longer present at all, so the statement is dead weight.
  • Now fixable — a real upstream fix exists, so the finding should be patched, not hidden.

VEX documents are also schema-validated in CI. The workflow is documented in tools/vex/README.md.

Check it yourself

Every claim here is verifiable from your terminal without an account — see Verify.