Safeguard
Container Security

Container Image Scanning Best Practices

A practical guide to container image scanning: when to scan, what to block, what scanners like Snyk miss, and how to build a policy that actually gets remediated.

Karan Patel
Cloud Security Engineer
8 min read

In March 2024, a maintainer noticed a 500-millisecond SSH login delay and uncovered the xz-utils backdoor (CVE-2024-3094) — a supply chain compromise embedded two minor versions deep in a compression library that ships inside thousands of base container images. Three years earlier, Log4Shell (CVE-2021-44228) forced teams to ask a question most couldn't answer quickly: "which of our running containers actually contain this library?" Docker Hub now hosts more than 15 million public repositories, and Snyk's own 2023 State of Cloud Native Security report found that over 75% of container images shipped to production carry at least one high or critical vulnerability. Container image scanning — the practice of inspecting image layers, packages, and metadata for known vulnerabilities, misconfigurations, and secrets before and after deployment — is no longer a compliance checkbox. This post breaks down what actually works, where popular tools like Snyk fall short, and how to build a scanning program that catches issues before they ship.

What Is Container Image Scanning, and Why Does It Matter Right Now?

Container image scanning is the automated process of unpacking an image's layers and comparing every installed package, library, and OS component against vulnerability databases like the NVD, OSV, and vendor-specific feeds. It matters right now because the average container image is built from someone else's work: a 2023 analysis of public Docker Hub images found that a typical application image inherits 30 to 60 transitive OS packages from its base image alone, most of which the application team never explicitly chose. When the xz-utils backdoor surfaced in March 2024, organizations with continuous image scanning identified affected containers within hours; teams relying on quarterly audits took weeks to confirm exposure. Scanning closes that gap by giving you an inventory — effectively a live software bill of materials (SBOM) — every time an image is built, not just when someone remembers to check.

How Often Should You Actually Scan Container Images?

You should scan at three distinct points — build, registry, and runtime — because a vulnerability-free image today can become vulnerable tomorrow without a single line of your code changing. A build-time scan catches issues before an image is pushed, ideally as a blocking CI step that fails on critical, fixable CVEs. A registry scan re-checks every stored image on a recurring basis — Safeguard customers typically run this every 24 hours — because new CVEs are disclosed daily against packages that were "clean" when the image was built; the NVD published over 29,000 CVEs in 2023 alone, an average of roughly 79 per day. A runtime scan checks what's actually executing in production, since drift, hot-patching, or exec access can change a container's real contents after deployment. Teams that only scan at build time routinely discover, during an incident, that the image running in production is weeks or months older than the one they last scanned.

Should You Fail the Build, or Just Report the Findings?

You should fail the build only for vulnerabilities that are both severe and fixable, because a scanner that blocks every CI run on unfixable transitive CVEs trains developers to ignore it entirely. A common, workable policy: block on critical and high-severity CVEs with a published fix available, and route everything else — including critical CVEs with no fix yet, like many zero-days in the days after disclosure — into a tracked backlog with an SLA (for example, 7 days for critical, 30 days for high, 90 days for medium). This mirrors how Log4Shell played out in practice: the initial CVE-2021-44228 disclosure on December 9, 2021 had a fix within 24 hours, but two follow-on CVEs (CVE-2021-45046 and CVE-2021-45105) were still being patched into January 2022, meaning a rigid "block everything" policy would have halted deployments for weeks. Policy-as-code, not a single global severity threshold, is what makes scanning sustainable at scale.

What Do Container Scanners Typically Miss?

Most scanners are tuned to catch known-CVE matches in package manifests, but they typically miss exposed secrets baked into layers, misconfigured base images, and license risk — three categories that cause real incidents. A 2023 GitGuardian study found that roughly 1 in 100 public Docker Hub images contained at least one hardcoded secret, such as AWS access keys or private certificates, left behind in an intermediate build layer that docker history never surfaces in a normal review. Scanners also frequently miss configuration issues like containers running as root by default (still the default in a large share of official images unless explicitly overridden) or images built FROM ubuntu:latest, which silently pulls a different, unpinned image on every rebuild. Snyk and similar CVE-focused tools are strong on package vulnerability matching but historically weaker on catching secrets embedded in earlier layers that get squashed out of the final image view — which matters because a secret baked into layer 3 of a 12-layer image is still extractable even if layer 12 never references it.

How Does a CVE-Focused Scanner Like Snyk Compare to a Full Supply Chain Approach?

A CVE-focused scanner like Snyk answers "does this image contain known-vulnerable packages," but it doesn't answer the broader question of "can I trust where this image came from and everything that touched it on the way here." Snyk built its reputation on developer-friendly vulnerability scanning integrated into IDEs and CI pipelines, and that's genuinely useful for catching the 79-CVEs-a-day drumbeat of package vulnerabilities. But container supply chain risk extends past known CVEs: it includes provenance (was this image built from the source it claims to be?), SBOM completeness across all layers, base image drift between what was scanned and what's deployed, and registry-level tampering. The 2020 SolarWinds compromise and the 2024 xz-utils backdoor both involved components that had no known CVE at the time of injection — meaning a pure vulnerability-matching scan would have shown a clean report on a compromised artifact. Organizations relying solely on CVE scanning get strong coverage for the ~90% of incidents that involve known, disclosed vulnerabilities, but limited protection against the supply chain attacks that don't.

What Does a Mature Container Scanning Policy Actually Look Like?

A mature policy scans continuously across the full lifecycle, ties findings to ownership, and enforces graduated response times rather than a single pass/fail gate. In practice that means: every Dockerfile change triggers a build-time scan gating the merge; every image push to a registry (Docker Hub, ECR, GCR, or ACR) triggers a full SBOM generation and vulnerability match; every image already in a registry gets re-scanned at least daily against updated CVE feeds; and every running container in production is periodically reconciled against its scanned image digest to catch drift. Ownership matters as much as tooling — a 2023 Sysdig cloud security report found that 87% of container images contained a high or critical vulnerability, but only a fraction of scanned findings were ever remediated, largely because no single team was accountable for base image updates. Assigning image ownership at the repository level, and routing findings directly to that owner instead of a shared security queue, is consistently what separates teams with declining vulnerability counts from teams that accumulate backlog indefinitely.

How Safeguard Helps

Safeguard was built around the idea that a clean CVE scan is necessary but not sufficient — you also need to know where an image came from and whether anything changed between build and deployment. Safeguard scans container images at build time, registry time, and runtime, generating a complete SBOM for every layer (not just the final squashed view) so that secrets and misconfigurations buried in intermediate layers don't slip through the way they can with layer-only summaries. Every scanned image gets a cryptographically verifiable provenance record, so teams can confirm an image was built from the source and pipeline it claims, closing the gap that pure vulnerability-matching tools like Snyk leave open against supply chain attacks with no assigned CVE.

Policy enforcement in Safeguard is configurable by severity, fixability, and exploitability — not just a single global threshold — so teams can block critical, fixable CVEs at the CI gate while routing everything else into owner-assigned queues with SLA tracking, matching the graduated response model that mature security programs actually use. Registry-wide continuous re-scanning runs on a rolling schedule against updated CVE feeds, so a newly disclosed vulnerability like a future Log4Shell or xz-utils-style backdoor surfaces against every affected image already in your registries within hours, not at the next scheduled audit. Runtime reconciliation flags any container whose live digest has drifted from its last scanned image, closing the build-time-only blind spot that leaves teams running unscanned production workloads without knowing it. For teams that have outgrown a single-purpose vulnerability scanner and need image scanning as one piece of a full software supply chain security program, Safeguard connects the scan result to the artifact's actual origin and lifecycle — not just its package list.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.