Cutting vulnerability noise: using AI and public data to demote CVEs that don't matter

by

in artificial-intelligence,cyber-security,

August 21, 2026

A container image scan finishes and hands back a few hundred findings. A dozen are critical. Most of the rest are base image packages with a CVE ID, a CVSS score, and no patched version anywhere in the world. The team has one afternoon a fortnight for this work. Where do they start?

Usually they start by scrolling, and that is the whole problem. When a report is 90% unactionable, people stop reading it, and the one finding that did have a fix available gets the same amount of attention as the 200 that did not. Noise is not just annoying. It is the mechanism by which real vulnerabilities get missed.

This post is part of our Practical AI in Cyber Security series, and it covers something we run for clients rather than something we think would be nice: cross-referencing scanner output against public vulnerability data so that findings with no available fix get demoted automatically, and findings with a released fix stay loud.

What “no fix available” actually means

Scanners report what a package version is vulnerable to. They are much less consistent about whether anyone has shipped a repaired version.

The distinction matters because the two cases need completely different responses. If Debian, Alpine, Ubuntu or Red Hat has published a fixed package, the answer is to bump the version and rebuild, which is an hour of work. If the upstream maintainer has marked the issue as won’t fix, disputed, or minor, or the affected code path is not compiled into the distro build at all, there is nothing to install. The only available responses are compensating controls, removing the package, or accepting the risk and writing it down.

Both arrive in the report looking identical. A CVSS 7.5 with a fix and a CVSS 7.5 without one sit next to each other, sorted by severity, as though they are the same kind of work item.

The pipeline

The approach is deliberately boring. Deterministic data does the demotion, and AI is confined to the parts that are genuinely unstructured.

  • Normalise scanner output into one record per finding: CVE ID, package name, installed version, ecosystem, image or host, and where it runs.
  • Query OSV.dev for each package and version. OSV aggregates advisories across language ecosystems and Linux distributions and returns affected version ranges, including whether a fixed version exists for that specific distro build.
  • Apply the rule. A finding with a fixed version in the ecosystem the package actually came from stays at its original priority. A finding with no fixed version anywhere, and no runtime exposure flag, drops to a demoted queue that gets reviewed monthly rather than fortnightly.
  • Everything demoted keeps its full record, with the reason, the advisory that justified it, and the timestamp of the data the decision was made on.
  • Feed the promoted findings into the ticketing system the team already uses, one ticket per rebuild rather than one per CVE.

For clients with several environments, the fetch and reconciliation runs as a scheduled integration job. We use Centazio, our open source data integration platform, for this sort of thing, because the hard part is not the API call, it is keeping the state consistent across repeated runs and knowing which records are stale.

Where AI helps, and where we keep it out

The demotion decision itself is not an AI decision. Version comparison is a solved problem and it should stay deterministic, because a language model that occasionally hallucinates a fixed version is worse than no enrichment at all.

Three things in this pipeline are messy enough that a model earns its place. The first is advisory prose. Distro advisories and upstream issue trackers explain in free text why something is not being fixed, and a model summarising twenty of those into “these six are all the same unfixed glibc locale issue” saves real reading time. The second is clustering: grouping 180 findings into the eight base image rebuilds that would resolve them. The third is drafting the risk acceptance note, which a human then edits and signs.

Note the pattern. The model reads, groups and drafts. It never decides on its own that something is safe to stop looking at. Practitioners are still asking each other what tooling exists for reviewing AI-assisted work in engineering pipelines, with no settled answer as of August 2026, so designing around a verification step rather than trust is the sensible default. It is also worth being explicit with stakeholders about where the model sits, because audiences in 2026 scrutinise disclosed AI use closely, and a security control nobody trusts does not get used.

Fail noisy, not fail quiet

The dangerous failure mode is obvious once you name it: the enrichment source is unreachable, every lookup returns nothing, “no fixed version found” is indistinguishable from “no answer received”, and the whole report quietly demotes itself to zero. The dashboard goes green on the day it should go red.

So the pipeline distinguishes the two cases at the type level and treats an unavailable source as a check failure:

def triage(finding, osv):
    try:
        advisory = osv.lookup(finding.cve, finding.package, finding.ecosystem)
    except (TimeoutError, HTTPError) as e:
        raise EnrichmentUnavailable(finding.cve) from e   # alerts, does not demote

    if advisory.age > MAX_CACHE_AGE:
        raise EnrichmentStale(finding.cve, advisory.age)

    if advisory.fixed_versions:
        return Priority.ORIGINAL
    if finding.runtime_exposed:
        return Priority.REVIEW
    return Priority.DEMOTED

Two rules follow from that. Findings that could not be enriched keep their original severity and are flagged as unenriched, so a broken run produces a louder report than a healthy one. And the cached advisory data carries a maximum age, because silently triaging today’s images against a three week old snapshot is the same bug wearing a disguise.

The economics for a lean team

Most Australian organisations we work with have two or three people covering infrastructure, patching and everything else. Their real constraint is rebuild cycles, not knowledge. They know the base image is old.

The value of demotion is that it makes the remaining queue small enough to finish, which is what turns patching into a habit instead of a quarterly panic. The ACSC’s Essential Eight expects patches for applications and operating systems to be applied within defined windows and expects you to demonstrate it. A queue of fifteen fixable findings can be closed and evidenced. A queue of three hundred, mostly unfixable, cannot, and the auditor sees the same wall of red the engineers gave up on.

Honest limitations. Version matching across distros is fiddly, because backported patches leave the version string looking unfixed when the vulnerability is already gone, so expect a tuning period and some manual overrides. Demoted is not deleted: the monthly review exists because a package with no fix today may get one next Tuesday, and a re-query catches that. Runtime reachability, which would let you demote far more aggressively, needs instrumentation most teams do not have, so we treat exposure as a coarse flag rather than a proof. And the LLM step costs a few dollars a month at typical volumes, which is nothing next to the engineering time to set the pipeline up and keep the version comparison honest. That build effort is the real cost, and it is worth it only if someone is going to work the shortened queue.

PicNet builds production AI systems for Australian organisations. Talk to us about what a first project could look like.

Tagged: #vulnerability-management #cve #patch-management #devsecops #osv