Docker image scanning in CI is a best practice that can become a liability. The intent is sound: scan every image build to catch CVEs before they reach production. The outcome is often a high-noise process that slows pipelines, produces findings that teams cannot act on, and eventually gets disabled or excepted to the point of irrelevance.

The teams that make CI scanning work sustainably have solved a different problem than the teams still fighting scanner fatigue. They have addressed the structural issues that make scanning painful, not just the configuration issues.


Why Scanning Slows Teams Down?

The volume problem: A typical base image scan returns 100-300 findings. Most findings are in packages the application never uses. Every finding requires triage: is this real risk? Is this in the execution path? Who owns it? The triage burden per build adds up to engineering time that scales with CVE count, not with actual risk.

The threshold problem: A scan gate that blocks deployments requires a threshold. Set the threshold at zero Critical CVEs, and base images fail every build — legitimate deployments are blocked while the team waits for upstream patching. Set the threshold high to avoid blocking deployments, and the gate is meaningless.

The unreachable findings problem: Many scan findings are in packages that the application team cannot patch. A libssl CVE in the OS layer of a Debian base image requires either waiting for the Debian maintainers to release a patch or switching base images. Neither is something a developer can do in the afternoon to unblock their deployment. The finding is real, but the developer has no path to resolve it.

These three structural problems make scanning feel like overhead rather than security improvement. The scanner is working as designed; the problem is what scanning alone can accomplish.


Hardening Before Scanning: The Structural Fix

The effective solution is inserting an automated hardening step before the scan gate runs for policy evaluation. The sequence:

Build image → Profile & harden → Scan hardened image → Policy gate → Push

Instead of scanning the raw base image plus application code (which carries 100-300 CVEs), the gate evaluates the hardened image that has had unused packages removed.

This changes the scan outcome fundamentally:

  • CVE count drops to only those in executed packages (typically 10-30 for most applications)
  • Threshold of “zero Critical CVEs” becomes achievable for the hardened image
  • Remaining findings are in packages the application actually uses — findings the team can prioritize and address
  • The “we cannot patch OS packages” problem is solved because those packages have been removed

Container vulnerability scanning tool integration that includes hardening before the policy scan converts the gate from a check on what was inherited (mostly uncontrollable) to a check on what the application actually needs (actionable).


Pipeline Performance

Scanning adds time to CI builds. For large images, scans can add several minutes. At the scale of dozens of builds per day across dozens of services, this accumulates.

Reducing image size through hardening produces a secondary benefit: smaller images scan faster. A 200 MB hardened image scans in a fraction of the time required for a 500 MB unminimized image. The hardening step adds some build time, but the reduction in scan time — combined with the reduced triage time from fewer findings — nets out positively for most organizations.

At very high build frequencies, caching strategies matter:

# GitHub Actions: cache hardened base image to avoid rehardening on every build

– name: Cache hardened base

  uses: actions/cache@v3

  with:

    path: /tmp/hardened-base.tar

    key: hardened-base-${{ hashFiles(‘base-image-version.txt’) }}

– name: Load or harden base

  run: |

    if [ -f /tmp/hardened-base.tar ]; then

      docker load < /tmp/hardened-base.tar

    else

      harden-base-image python:3.12-slim hardened-base:latest

      docker save hardened-base:latest > /tmp/hardened-base.tar

    fi

The hardened base changes only when the base image version changes, not on every build. Application-layer hardening runs on each build but is faster than full-image hardening because the base layer is already processed.


Routing Remaining Findings

The findings that remain after hardening are in packages the application actually executes. These findings are genuine work:

Finding CategoryOwnerAction
CVE in executed application dependencyApplication teamUpdate package version
CVE in executed runtime library (Python, Node runtime)Platform teamBase image update
CVE with no fixed version, executed packageSecurity teamRisk acceptance with documentation
CVE in executed package where fix breaks compatibilityApplication + securityCompatibility testing + patching

The container image tool workflow that routes findings by category gives each type of finding a clear owner and action. Developers working on application dependencies get findings they can fix. Platform teams managing base images get findings that require base image updates. Security teams get the residual findings that require risk decision-making.

This routing structure is the difference between scan results that drive action and scan results that accumulate in a shared backlog with no clear owner.



Frequently Asked Questions

Why does Docker image scanning in CI produce so much noise?

Docker image scanning in CI returns large numbers of findings — typically 100-300 per build — because standard base images include hundreds of packages for general compatibility, most of which the application never uses. Developers must triage each finding to determine whether it represents real risk, and most findings are in OS packages they have no direct path to patch. This structural volume problem makes scan results feel like overhead rather than actionable security data.

How can I integrate Docker image scanning into CI without slowing down builds?

The most effective approach is inserting an automated hardening step before the policy scan: build the image, profile and harden it to remove unused packages, then scan the hardened image. This reduces CVE counts from 100-300 to 10-30, making thresholds achievable and scan time faster since smaller images scan in a fraction of the time. Caching the hardened base image across builds — only re-hardening when the base image version changes — further minimizes the time impact of adding hardening to the pipeline.

What CVE threshold should I set for Docker image scanning in CI?

Set the threshold against the hardened image, not the raw build output. Against a hardened image carrying only CVEs in executed packages, a threshold of zero Critical CVEs is achievable for most applications and worth enforcing. Against an unminimized image carrying inherited base CVEs, any strict threshold will block legitimate deployments continuously. The threshold level matters less than whether it is applied to hardened or unhardened output — the same zero-Critical rule that fails every raw build will consistently pass hardened builds.

Who should own CVE findings from Docker image scanning?

Findings remaining after hardening fall into clear ownership categories: CVEs in application dependencies belong to the application team for package version updates; CVEs in executed runtime libraries belong to the platform team for base image updates; CVEs with no available fix belong to the security team for documented risk acceptance. Routing findings by category rather than dumping everything into a shared backlog gives each type of finding a clear owner and action, which is the difference between a scan result that drives remediation and one that accumulates indefinitely.


Measuring Improvement

The signal that scanning integration is working well:

  • Gate pass rate on first build: Teams whose images consistently pass the security gate without modification have practices that produce clean outputs.
  • Mean findings per image: Trending downward indicates that hardening and upstream patching are keeping pace with CVE disclosures.
  • Time from finding to remediation: For the genuine findings that remain after hardening, how quickly are they resolved? This tracks whether the remaining finding set is manageable.
  • Rate of gate exceptions: Rising exception rates indicate that thresholds are set wrong or that hardening is not reducing CVEs sufficiently.

CI scanning that produces these metrics is not overhead. It is a measurement system for container security health, generating data that security leaders and development managers can use to track posture over time.