A scan finishes and half the findings turn out to be noise. Before you write a suppression rule, it helps to know which of a small number of mechanisms actually produced the false positive, because each one needs different proof before you can close it with confidence. Below are the seven causes that account for most of what analysts triage away, what evidence actually closes each one, and why the shortcut of a blanket exception rule tends to cost you later.
The seven real causes
1. Banner and version inference without behavioral proof
Most network scanners still identify a service by grabbing a banner, a response header, or a handshake fingerprint and mapping it to a CPE string. A web server that returns Server: Apache/2.4.41 gets flagged for every CVE registered against 2.4.41, even when the vulnerable code path was never compiled in, or the header was set manually to something unrelated to the real binary. Version strings are configuration, not proof of the code that is actually running.
2. Backported security fixes
Enterprise Linux distributions patch CVEs into old package versions without bumping the version number. Red Hat, Debian, and Ubuntu all do this as a matter of policy. A scanner that only compares the reported version against the first fixed upstream version will flag a system that has actually been patched for months. This is the single most common source of false positives on any host running RHEL, CentOS Stream, Debian stable, or Ubuntu LTS.
3. Unreachable code paths
A vulnerable function can exist in a binary or library without ever being reachable from an attacker-controlled input. A PHP extension with a known deserialization bug that is loaded but never invoked by any code path the application actually executes is not exploitable in that deployment, even though the library version matches the advisory exactly.
4. Compensating controls and mitigations
A vulnerable configuration can be present and still not exploitable because something else in the stack blocks the trigger condition. Disabled scripting engines, a WAF rule that strips the malicious parameter before it reaches the application, seccomp profiles, or a feature flag that turns off the vulnerable code path all fall into this category. The CVE is real, the affected version is real, and the finding is still not actionable until someone checks whether the mitigation is actually in place and not just assumed.
5. Proxy, load balancer, and WAF interference
Reverse proxies and WAFs rewrite headers, inject their own banners, and sometimes respond to probes on behalf of the backend. A scanner hitting a CDN edge or a Sucuri/Cloudflare-fronted origin can fingerprint the edge device instead of the origin server, producing findings that apply to infrastructure the customer does not manage and cannot patch. This shows up constantly in external scans of anything sitting behind a CDN.
6. Stale plugin and signature logic
Scanner vendors ship thousands of detection plugins, and not all of them get maintained at the same pace as the CVE database. A plugin written against an early disclosure sometimes checks a condition that was later found to be wrong, or it keys off a registry value or file path that changed between minor versions of the target software. Nessus, OpenVAS, and Qualys have all shipped plugins that were later revised or retracted for exactly this reason.
7. Misidentified operating system
OS fingerprinting via TTL values, TCP window size, or nmap -O probability scoring is a guess, not a certainty, especially through NAT, VPN concentrators, or virtualization layers that normalize these values. When the OS guess is wrong, every OS-specific check inherits that error, and you get a pile of findings for patches that do not even apply to the platform in question.
How to tell a false positive from an unconfirmed true positive
These are not the same thing, and treating them as the same thing is how backlogs grow. A false positive means you have evidence the vulnerable condition does not hold on this asset: the patch is installed, the code path is unreachable, the mitigation is confirmed active. An unconfirmed true positive means you have not yet gathered that evidence, whichever way it points. The practical test is simple: can you name the specific artifact, a package changelog entry, a config file, a response from an authenticated check, that would flip your classification? If yes, you have an unconfirmed finding sitting in queue, not a false positive. If you cannot name what evidence would change your mind, you are pattern matching on gut feel, and that is exactly how real findings get closed by mistake.
Evidence you need before closing a finding as FP, per cause type
Each cause above has a specific artifact that closes it. Generic statements like “verified, not applicable” without an attached artifact are not evidence, they are just a label, and they will not survive an audit or a post-incident review.
| Cause | Evidence that actually closes it |
|---|---|
| Banner inference | Authenticated check of the actual installed package version and build, not the advertised header |
| Backported fix | Vendor changelog or security advisory entry, e.g. rpm -q --changelog output or the Debian security tracker page showing the CVE marked fixed |
| Unreachable code path | Static or dynamic call-graph evidence, or a config dump showing the module is not loaded or the route is not registered |
| Mitigation present | Live confirmation the control is enforced now, e.g. the WAF rule ID and a request log showing it firing, not a change-ticket reference from a year ago |
| Proxy/WAF interference | Direct scan of the origin IP, bypassing the edge, with a second finding that agrees or disagrees |
| Stale plugin logic | Vendor plugin changelog or a manual reproduction of the check’s actual test condition against the live asset |
| Misidentified OS | Authenticated fingerprint, e.g. /etc/os-release, registry build number, or agent-reported OS |
Why blanket exception rules quietly hide real issues later
The fastest way to clear a backlog is to suppress by CVE ID, by plugin ID, or by asset tag, and it is also the fastest way to build a blind spot that nobody notices until an incident. A rule that says “suppress CVE-2023-XXXXX on all hosts tagged web-tier” was written against the evidence available for the hosts that existed when the rule was made. Six months later a new host joins that tag with a different patch level, and the suppression silently swallows a real finding on it. The same failure mode applies to plugin-level suppressions after a scanner vendor revises the plugin logic, the exception no longer matches the condition it was written for, but it keeps suppressing anyway because nothing forces a review. Any exception rule should carry an expiration date and a re-validation trigger tied to the next scan cycle, not a permanent, unreviewed lifetime. If your tooling cannot tell you when a suppression rule was last checked against current conditions, treat that as a gap, not a convenience.
Measuring your FP rate per scanner so tuning has a baseline
You cannot tune what you have not measured, and “false positive rate” without a denominator is meaningless. Track it per scanner, per finding category, over a fixed window:
- FP rate = findings confirmed as false positive with evidence / total findings closed in the period, broken out by scanner and by CVSS band
- Track separately for network scanners, web application scanners, and container/image scanners, because their failure modes above do not overlap much
- Watch the trend after every scanner engine or plugin feed update, a spike right after an update usually points to cause 6, stale or newly changed plugin logic, not a real increase in your attack surface
- Set a review threshold, for example anything above 15 to 20 percent FP rate on a given scanner and severity band justifies a tuning pass on scan credentials, authenticated scanning coverage, or plugin selection before you trust that scanner’s output for prioritization
Without this baseline, every conversation about “the scanner is too noisy” is an opinion. With it, you can show whether a specific engine, a specific asset group, or a specific severity band is where the noise concentrates, and fix that instead of tuning everything indiscriminately.
When validation should be automated instead of manual
Manual triage does not scale past a few hundred findings a week, and the seven causes above are each checkable with a repeatable, scriptable test: pull the package changelog, check whether the module is loaded, confirm the WAF rule is active, re-scan the origin IP directly. Once a check is repeatable, it belongs in an automated validation step rather than in an analyst’s head. Platforms that automate this phase, such as SITEY, run these per-cause checks against each raw finding before a human ever sees it, so what lands in the queue is either confirmed exploitable or flagged with the specific missing evidence, rather than a flat list of unverified scanner output. The same logic applies at the other end of the lifecycle: after a patch or config change ships, the finding should be re-tested against the original proof-of-concept rather than closed on the assumption that the patch command exited cleanly, since a package manager reporting success is not the same evidence as the vulnerable condition actually being gone.
The dividing line for what to automate versus what still needs a human is reachability and business context. Package version comparison, changelog lookups, and WAF-rule-active checks are mechanical and safe to automate outright. Whether an unreachable code path might become reachable after a planned feature launch, or whether a compensating control is acceptable for a specific compliance scope, still needs a person who understands the deployment. Automate the repeatable evidence-gathering, keep judgment calls on ambiguous business risk with an analyst, and route only the confirmed, evidence-backed findings into your triage workflow so the queue reflects real risk rather than raw scanner volume.
Consolidating output from multiple engines through a single scanner integration layer also reduces a specific subset of these false positives on its own, because overlapping findings from two different scanners on the same asset either corroborate each other or expose exactly which one is wrong, which is faster than investigating either finding in isolation. And once a fix ships, closing the loop through a proper retest and closure step, rather than trusting the deployment log, is what prevents the mirror problem: a false negative where a finding gets marked resolved while the underlying condition is still there.
About SITEY
SITEY is an autonomous vulnerability management platform. It discovers, validates, prioritizes,
remediates and re-tests vulnerabilities through an eight-phase automated pipeline, unifying output
from 17 integrated scanners.Findings are stored in your own database. Outbound connections are limited to licence activation and the optional services you enable, such as an AI provider, CVE enrichment and patch catalogues. Pricing is 599 USD per month or 5,999 USD for a perpetual lifetime
license. See pricing or how the platform works.