Honest reporting
A scan that couldn't check isn't a clean scan
A scanner's worst failure isn't a crash. It's reporting a clean result it never actually established. CveDeck keeps "no findings" separate from "didn't find out".
The meanings of "0 findings"
A fleet row reading web-01 · linux · success · 0 0 0 0 can mean any of these.
Only the first is good news, and CveDeck reports each one distinctly.
-
Clean
The host is genuinely clean. Every configured source answered, and nothing matched.
-
Partial
An advisory source was unreachable during the scan. The result is marked partial and raises a warning, never shown as clean.
-
Stale
The host was scanned long ago and nothing has looked since. Scan age is shown on every host, and scans older than seven days are flagged as stale.
-
Never scanned
The host was enrolled but never scanned. It says so, in a neutral state, rather than showing a failure for a connection nobody tried to make.
-
Inventory unavailable
The scan connected, but nothing could tell it what was installed. An unsupported distribution, a locked package database, a restricted shell, a container with no package manager. This is the most dangerous of the five: a host with no readable inventory looks exactly like a host with nothing installed, so it used to be recorded as a successful scan of zero packages — which cleared every finding the previous scan had found and reported them all as resolved. It's now its own status, carrying the reason, and it writes no findings at all.
Only real outages count as partial
Each scan records whether every configured advisory source answered. A failed lookup reaches the matcher as a failure, not as an empty answer, so a source outage can't quietly turn into "no advisories".
Only configured sources count. NVD matching is off by default, and a deployment that hasn't turned it on doesn't get every scan branded partial. That would train people to ignore the warning. When NVD is enabled, a rate-limited request counts as a real outage, so a throttled scan reports partial.
A partial scan keeps what it couldn't re-check. Findings the silent source would have reported stay on the host exactly as they were, and nothing is counted as resolved, because an unreachable source is not a patch.
Failures that tell you what failed
An unreachable host and failed SSH authentication are reported as failures, not as hosts with zero findings. Each failure carries the original error message, so you can tell a wrong password from a rejected key, or a DNS failure from a filtered port.
A pre-flight connection test reports reachability, credentials and the OS banner before you commit to a scan. It dials the same SSH port a scan does.
A host whose SSH key changed gets its own status. CveDeck pins each host's key the first time a connection to it succeeds, and a host that later presents a different one is refused before any credential is sent, as Host key changed, with both fingerprints in the message. It isn't filed under "couldn't connect", because the two mean different things: one is a host that's down, the other is something answering in its place. A host you've rebuilt clears with Forget host key.
What the last scan actually changed
After a patch round the question is what that cleared, and whether anything is new. Every
scan is kept with the findings it found new and the ones it cleared, so the fleet reads
+3 new / −5 resolved and each finding carries the date it first appeared. A diff can lie in
the same ways the rest of this page exists to prevent, so the same rule holds: when CveDeck doesn't know,
it says so.
- A partial scan resolves nothing. Its resolved count is stored as not assessed and shown as a dash with the reason, never as 0. "0 resolved" would claim an outage proved nothing was patched.
- A failed scan changes nothing. The run is recorded with its status and no counts, and the host keeps the findings from its last successful scan.
- The first scan is a baseline. With nothing to compare against, it reports neither new nor resolved findings, rather than calling every existing finding new.
- Same CVE and same package means the same finding, whatever the version. A package upgraded to a newer build that's still vulnerable is one problem still open, not one resolved and one new, which would inflate both counts after every partial upgrade.
- A scan never closes a remediation record. Remediation is a person's statement. A finding a scan clears while its record still says In Progress is shown as exactly that, and you decide whether the record is done.
Unenriched is not unexploited
The same failure mode appears one level down, in threat intelligence. If no usable CISA KEV catalog existed when a finding was recorded, its exploitation status is unknown, not "not exploited".
Collapsing unknown into "no" would produce the worst available outcome: a dashboard reporting "0 actively exploited" across a whole fleet, on the authority of a catalog that was never downloaded. CveDeck shows a muted dash instead, raises a banner when a feed is stale or unusable, and reports each feed's age through its API.
The three exploitation states are explained with the ranking.
A summary can't be more confident than its rows
Keeping "unknown" out of the rows is only half the job. The line above the table is the part people actually read, and for a while it was entitled to a confidence the table underneath it wasn't.
A host's summary used to ask whether any finding had been checked against CISA's catalog. One checked-and-absent finding among forty unchecked ones was enough to print "None actively exploited" — directly above a table correctly showing those forty as unknown. The summary and its own table disagreed, and nobody audits a host row by row to see whether the headline has earned its confidence.
A host is presented as clear only when every finding on it was checked. A partially checked one says how far it got — "1 of 41 checked, none exploited so far" — and carries the quiet styling of an unknown rather than the settled styling of a clear result, because the styling is read before the words are.
The fleet table carries the same four states, for the same reason. It used to gate its zero on whether the feed was healthy fleet-wide, which answers a weaker question than the column asks: a host re-scanned while a feed was down holds findings nobody checked, however healthy that feed looks afterwards.
| Shown | Means |
|---|---|
| 4 | Confirmed: findings on this host are on the catalog. |
| 0 | Every finding was checked, and none is listed. |
| 0 so far | Some were checked and none is listed. Others were never checked. |
| — | None were checked. "0 so far" would imply somebody asked. |
That last distinction is the whole argument in miniature. "0 so far" and a dash both decline to claim a host is clear, but only one of them claims anyone looked.
Installed isn't the same as running
A host can have every package updated and still be running the vulnerable kernel it booted from. A scanner that only reads the package list reports that host as clean.
CveDeck's Linux collector also reads the running kernel and the pending-reboot
state: /var/run/reboot-required on Debian and Ubuntu, needs-restarting -r
on the RHEL family. Where a distribution offers no read-only way to ask, the state is recorded as
indeterminate rather than guessed.
Refusing a scan rather than faking one
Windows hosts can be discovered and enrolled, but CveDeck can't yet match Windows software or cumulative updates against vulnerability data. A Windows scan would finish with no findings, which looks exactly like a clean host. So Windows scans are refused, with that reason, and the host stays enrolled and never scanned.