CVE classification
How the portal partitions scanner output into Outstanding patches vs Won't fix vs Awaiting upstream.
The single most important thing to understand about PodArmor's CVE numbers: we partition the scanner's raw output into Outstanding patches (actionable) and Transparency residuals (no available fix). The headline number a customer sees is the Outstanding count; the residuals are disclosed inline with one-click links to the maintainer's own ruling.
This is the same split Chainguard, DHI, and Minimus apply for their "zero CVEs" headlines. We just label it more honestly and link the audit trail.
The four scanner states
When grype scans an image, every CVE entry comes back with a fix.state:
fix.state | What it means | Our partition |
|---|---|---|
fixed | A patched version exists upstream. Pull the newer tag and the CVE goes away. | Outstanding |
not-fixed | The CVE is acknowledged but no patch has shipped yet. | Residual (subcategory: "Awaiting upstream") |
wont-fix | The maintainer has explicitly ruled this CVE does not require a patch. | Residual (subcategory: "Won't fix") |
unknown | The scanner couldn't classify it (typically GHSA / RustSec advisories without enough metadata to attribute to a package version). | Residual (subcategory: "Unclassified") |
The portal renders each of these with a small inline chip on the CVE detail row.
Why not-fixed is in residual
A not-fixed entry says: "the maintainer agrees this is a real CVE, but no patch exists today." There's nothing the customer can do today to address it — there's no package version to pin, no tag to re-pull. Counting it in the headline would make the count jump for reasons the customer can't address.
When the maintainer ships a patch, grype's next scan reports the CVE as fixed with a fixedIn value, and the entry automatically transitions from residual into Outstanding. The customer sees the count change the moment there's something to do.
How the headline rolls up
On every customer-facing surface — dashboard cards, image-detail KPI strip, side-by-side comparison panels, trust headline:
- "Outstanding patches" = count of CVEs where
fix.state === 'fixed' - "Transparency residuals" = count of CVEs where
fix.state ∈ {'wont-fix', 'not-fixed', 'unknown'}
The reduction percentages we compute against upstream (e.g. "100% fewer outstanding patches than eclipse-temurin:17-jre") use the Outstanding count on both sides. The "+ N residuals" foot-stat under the headline shows the raw total so an auditor running grype --quiet themselves sees a matching count.
What the audit trail looks like
Every residual entry in the portal has:
- A small label: Won't fix / Awaiting upstream / Unclassified
- A direct link to the CVE on
security-tracker.debian.org(for Debian-based images) — where the maintainer's ruling lives in writing - The original CVE id (CVE-, GHSA-, or RHSA-), the affected package, and the installed version
A procurement reviewer can verify any single "Won't fix" entry by clicking through to the tracker and reading Debian's own assessment. There's no PodArmor-internal classification involved — we're just rolling up what the maintainer has already published.
Why this matters for procurement
A naive scan of a hardened Debian-based image will show ~15-20 entries that the standard scanners (Snyk, Trivy, Prisma, Qualys) all flag. The unsophisticated framing is "you have 20 CVEs." The sophisticated framing — the one a CISO who knows Debian classifies CVEs accepts — is:
"Zero patches you'd actually have to apply. The remaining entries are residuals the maintainer has explicitly ruled don't require a patch. Here's the link to the maintainer's ruling for each one."
That's the framing this product surface is built around.