Managing false positives
The problem, stated plainly
A raw scan of a typical application image reports hundreds of alerts. A large majority are not exploitable in your context.
Untreated, there are two outcomes, both bad:
- the team tries to handle everything, burns out, and the real vulnerabilities drown;
- the team disables the checks, and the arrangement exists only on paper.
This is a compliance risk, not merely a comfort problem. An arrangement producing so much noise that nobody reads it does not demonstrate the “without delay” handling Annex I requires. Signal quality is a requirement, not a refinement.
Root causes
| Cause | Mechanism | Frequency |
|---|---|---|
| Imprecise matching | CPE correlation: homonyms, spellings, missing entries | Very high |
| Unreachable vulnerable code | The component is present, the vulnerable function is never called | High |
| Distribution backport | The fix is applied without changing the upstream version number | High on container images |
| Test dependencies counted | Dependencies never shipped appear in the product SBOM | High |
| Unused base image layers | Packages present in the image but never executed | High |
| Disputed or low-quality entries | An identifier published then disputed by the vendor | Moderate |
| Duplicate components | Two versions of one library, only one loaded | Moderate |
Remedies, by effectiveness
1. Prefer per-ecosystem identifiers. Correlating by purl against a per-ecosystem database
rather than by CPE against a general one cuts noise massively. It is the highest-return lever —
see Identifiers.
2. Populate the distribution. For system packages, stating the distribution and its version lets the tool apply the right fix database and ignore already-backported vulnerabilities.
3. Exclude test dependencies from the shipped product’s SBOM. They do not belong there — see Quality and completeness.
4. Reachability analysis. Determine whether the vulnerable function is called from your entry points. Expensive to set up, very effective thereafter.
5. Systematic VEX. Every discarded alert is documented by a VEX with a standardised justification. The alert leaves the dashboards without leaving the record.
6. Shrink the surface. Minimal base images, removal of unnecessary packages, controlled static compilation. Fewer components means fewer alerts — and less real risk.
7. Prioritise rather than filter. Use exploitation probability and confirmed-exploitation catalogues to order, not to remove.
Suppression policy
An alert may be set aside. It may not be erased.
| Permitted | Prohibited |
|---|---|
VEX not_affected with a standardised justification |
Silent suppression |
| Dated, reasoned muting with a named owner | Permanent muting |
| Documented exclusion of a file path | Globally disabling a check |
| Traced, contextualised severity reduction | Editing the vulnerability database by hand |
Every mute carries an expiry date. At expiry the alert reappears and the decision is re-examined. That is what separates an engineering decision from a workaround.
The box for Legal
Deciding not to fix is not a breach, provided the decision is reasoned, documented and traced. Annex I requires vulnerabilities to be addressed without delay; it does not require fixing every identifier a scanner reports.
A VEX is the legal form of that decision. Without it, a discarded vulnerability is indistinguishable from an ignored one — and that is exactly the distinction a surveillance authority will seek to establish.
The metric
Ratio of actionable alerts to raw alerts, measured per product and tracked over time.
ratio = alerts that led to an action (fix, workaround, reasoned VEX)
÷ raw alerts reported by the tools
A ratio of a few per cent signals a tooling problem, not excessive rigour. A steadily improving ratio signals a maturing arrangement. It is one of the rare metrics that measures the quality of the arrangement rather than its volume.
It appears in the dashboard described in Metrics.