Why your container vulnerability backlog is unmanageable
The count is not a measure of your risk, and treating it as one guarantees the programme fails. A container scanner enumerates every known vulnerability in every package present in the image, whether or not that package is ever loaded, reachable or exposed. A freshly built image from a mainstream base can produce hundreds of findings on its first scan, none of which you introduced. Getting to zero is not the goal and was never available.
Why does a new image produce hundreds of findings?
Because scanning is inventory matching, not analysis. The scanner reads the package manifests inside the image, resolves each to a version, and looks that version up in vulnerability databases. Every match is reported. It has no knowledge of whether your application ever calls the affected function, whether the vulnerable path requires local access you do not grant, or whether the component is a build-time artefact that never runs.
Severity compounds the problem, because the score attached to a CVE describes the worst plausible case for any user of that component, not your case. A denial of service in an XML parser scores highly in the abstract and means nothing in a service that never parses XML from an untrusted source. The scanner cannot know that. You can, and the entire value of a triage process is putting that knowledge somewhere the tooling can act on.
The practical consequence is that any policy phrased as a number will be abandoned. A gate that fails the build on any high severity finding will block every release within a fortnight, and the team will find the bypass rather than the fix, at which point you have both the backlog and a disabled control.
Which findings actually deserve attention?
A small proportion, and they are identifiable by type rather than by score. The categories below behave differently enough that treating them with one policy is the root cause of most unworkable backlogs.
| Finding type | Usually exploitable? | Right response | Natural owner |
|---|---|---|---|
| OS package CVE in the base image | Rarely on its own | Scheduled rebuild on a current base, not per-finding work | Platform team |
| Application dependency with a reachable call path | Yes, this is the real category | Patch, or pin and schedule, tracked like a bug | The service team |
| Vulnerable package present but never loaded | No | Suppress with a stated reason and an expiry date | Whoever suppresses it |
| Build tooling shipped into the runtime image | Not directly, but it widens what an intruder can do | Remove with a multi-stage build | Platform team |
| Misconfiguration: running as root, writable filesystem, no limits | More often the actual risk | Fix in the manifest, and gate on it hard | The service team |
| Credential baked into an image layer | Treat as already compromised | Rotate first, rebuild second, then work out how it got there | Security, immediately |
What actually reduces the count?
Rebuilding on a current base image on a schedule, which resolves most operating system findings without anybody reading them. The majority of what a scanner reports has already been fixed upstream, and the only reason it appears in your image is that the image was built months ago. A weekly automated rebuild converts a triage problem into a pipeline problem, and pipeline problems are the ones this discipline is good at.
The second lever is choosing a smaller base. Every package you did not install cannot be reported, and images built on minimal or distroless bases carry a fraction of the surface of a general purpose distribution image. This is genuinely disruptive if your application expects a shell or a package manager at runtime, which is worth knowing before promising it, and it is the change with the largest lasting effect on the numbers.
The third is multi-stage builds, so compilers, package managers and test tooling stay in the build stage. That removes a whole class of findings and, more importantly, removes the tools an intruder would otherwise find waiting for them inside a running container.
Why does a scanner go quiet three months after deployment?
Because nobody was given the triage job, and triage is the entire product. The installation is a day of work; deciding what a finding means, who fixes it and when it can be dismissed is a permanent responsibility. When that is unassigned, findings route to a channel, the channel gets muted, and the tool continues reporting into a room nobody is in.
Suppression without expiry is the second cause. A team facing a release blocked by a finding they know is irrelevant will suppress it, correctly, and if the suppression is permanent then a year later nobody knows whether it still applies. Suppressions that expire force a cheap re-decision, and they are the mechanism that keeps the list honest over time.
The third is a gate configured to fail on severity alone. Once it blocks a legitimate release, someone adds a bypass, and the bypass becomes the normal path. Any control that gets routinely bypassed is worse than no control, because it produces a record suggesting the check happened.
What policy survives contact with a release?
Gate on the things that are unambiguous and time-box the rest. Fail the build for credentials in the image, for a container configured to run as root without a stated exception, and for a finding that has a fix available above your agreed threshold. Do not fail it for findings with no available fix, because there is nothing the developer can do and the only outcome is a bypass.
Replace the count target with a freshness target. A commitment that no image running in production was built more than thirty days ago is measurable, achievable through automation and correlates with actual risk reduction far better than any number of resolved findings. It also gives the platform team a metric they control rather than one that depends on upstream maintainers.
Then hold a short review on a fixed cadence, where every suppression due to expire is either renewed with a reason or removed. This is unglamorous and takes under an hour. It is also the only part of the process that reliably distinguishes an organisation with container security from one with a container scanner.
What should you ask a vendor or a candidate?
Ask how a finding gets dismissed and what happens to that dismissal in six months. Any tool can list vulnerabilities. The difference between products, and between candidates, is whether they have thought about the lifecycle of a decision not to act, because that is where the workload actually sits.
Ask whether the tool can distinguish a package that is installed from one that is loaded at runtime, and whether it scans running workloads or only images in the registry. Those two capabilities change the size of the backlog by an order of magnitude, and their absence is the reason many teams cannot separate the fifty findings that matter from the two thousand that do not.
For a candidate, the revealing question is what their current false positive rate looks like and how they know. Someone who has run this in production will describe a specific triage routine, a suppression convention and an argument they lost with a security team. Someone who has only installed the tool will describe its dashboard.
Common questions
- Why does container scanning report so many vulnerabilities?
- Because it matches inventory rather than analysing risk. The scanner reads every package inside the image, resolves each version and reports every known vulnerability associated with it, regardless of whether the package is ever loaded or reachable from your code. Severity scores describe the worst plausible case for any user of that component, not your deployment, so a freshly built image from a mainstream base commonly produces hundreds of findings you did not introduce.
- How do you reduce container vulnerability findings?
- Three changes do most of the work. Rebuild images on a current base image on an automated schedule, which clears the majority of operating system findings because they are already fixed upstream. Move to a minimal or distroless base, since packages you never install cannot be reported. Use multi-stage builds so compilers, package managers and test tooling stay out of the runtime image. Per-finding triage should be reserved for application dependencies.
- Should a build fail on high severity vulnerabilities?
- Only when a fix is available. A gate that fails on severity alone will block legitimate releases within weeks, because many findings have no upstream patch and the developer can do nothing about them. The predictable result is a bypass that becomes the normal path, leaving you with a control that produces evidence of a check that did not happen. Gate hard on secrets in images and on misconfiguration instead.
- Who should own container vulnerability triage?
- Split it by finding type. Base image and operating system findings belong to whoever owns the image pipeline, because the fix is a scheduled rebuild rather than per-finding work. Application dependency findings belong to the team that chose the dependency, tracked like ordinary bugs. Secrets found in image layers belong to security immediately, and the first action is rotation rather than a rebuild.
- Why do container security tools stop being used after deployment?
- Because installation is a day of work and triage is permanent, and the triage job usually goes unassigned. Findings route to a channel, the channel gets muted, and the tool keeps reporting to nobody. The two mechanisms that prevent this are suppressions that expire, forcing a cheap re-decision on a schedule, and a short recurring review where every expiring suppression is renewed with a reason or dropped.
- What is a better target than zero vulnerabilities?
- Image freshness. A commitment that nothing running in production was built more than a set number of days ago is measurable, achievable through automation, and tracks real risk reduction better than a finding count that depends on upstream maintainers and database updates you do not control. It also gives the team a target they can influence directly, which is why it survives longer than a numeric backlog goal.