A single FROM node:18 line can quietly pull in 400+ transitive OS and language packages, any one of which might carry a known CVE. Container image scanning is the practice of inspecting an image's filesystem layers, package manifests, and metadata to find vulnerabilities, exposed secrets, and misconfigurations before that image ever reaches production. It's become the default control for shipping containers safely — Sysdig's 2024 Cloud-Native Security Report found that 87% of container images contain at least one high or critical vulnerability, and 60% of organizations reported a container-related security incident in the prior 18 months. Open-source scanners like Trivy (built by Aqua Security) popularized this workflow by making CVE scanning a free CLI command. But as teams scale from a handful of images to thousands across multiple registries, the gaps between "scanning" and "actually reducing risk" start to show. This post breaks down how scanning works, what it catches, how Trivy compares to alternatives, and where Safeguard fits.
What Is Container Image Scanning, and Why Does It Matter?
Container image scanning is the automated process of unpacking a container image, cataloging every OS package and application dependency it contains, and matching those against vulnerability databases to surface known CVEs. It matters because the average container image ships with software the engineering team never directly wrote or reviewed — base OS packages, language runtimes, and third-party libraries baked in at build time. Google's 2023 analysis of public container images found that the median image contained 30+ OS packages and often 100+ language-level dependencies (npm, pip, Maven, etc.) beyond the base layer. Each of those is a potential entry point. The 2021 Log4Shell vulnerability (CVE-2021-44228) is the canonical example: it lived inside a transitive Java dependency in thousands of containerized applications, and organizations without image scanning had no reliable way to even know they were exposed, let alone prioritize a fix.
How Does Container Image Scanning Actually Work Under the Hood?
Scanning works by extracting an image's layers, building a software bill of materials (SBOM), and diffing that SBOM against vulnerability feeds. Concretely, a scanner pulls the image (from a registry like Docker Hub, ECR, or GCR), unpacks each of its layers — typically stored as compressed tarballs per the OCI image spec — and walks the filesystem to identify package manager metadata: dpkg status files on Debian-based images, rpm databases on RHEL-based ones, apk databases on Alpine, plus lockfiles like package-lock.json, requirements.txt, or go.sum for application dependencies. That inventory becomes an SBOM, often expressed in CycloneDX or SPDX format. The scanner then cross-references each package name and version against vulnerability sources — the National Vulnerability Database (NVD), OS-specific advisories (Debian Security Tracker, Alpine's secdb, Red Hat's OVAL feeds), and language ecosystem advisories (GitHub Advisory Database, npm audit data). A full scan of a typical 500MB application image usually completes in under 30 seconds once databases are cached locally, since the heavy lifting is a lookup problem, not a compute-intensive one.
What Can Image Scanning Catch — and What Does It Miss?
Standard image scanning reliably catches known CVEs in OS packages and pinned dependency versions, but it structurally misses zero-days, logic flaws, and anything requiring runtime context. If a vulnerability has a published CVE ID and a version range, a scanner will flag it — that's the well-understood 80% of the problem. What it won't catch: a hardcoded AWS key committed into a layer (this needs secrets detection, a separate check most scanners bolt on), a malicious package inserted via a compromised build pipeline (the xz-utils backdoor, CVE-2024-3094, disclosed in March 2024, went undetected by version-matching scanners for weeks because the backdoored 5.6.0 and 5.6.1 releases weren't yet flagged as vulnerable — they simply hadn't been assigned a CVE yet), or a vulnerability that only manifests when a specific runtime flag is set. It also generally can't tell you whether the vulnerable code path is actually reachable at runtime — a critical CVE in a library function your application never calls still shows up as "critical" in most scanner output, which is a major driver of alert fatigue. Industry data backs this up: Endor Labs' 2024 dependency research found that roughly 71% of vulnerabilities flagged by traditional scanners were in code that was never executed in production.
How Does Trivy Compare to Other Scanning Tools?
Trivy, maintained by Aqua Security, is the most widely adopted open-source scanner because it's fast, free, and covers OS packages, language dependencies, IaC misconfigurations, and secrets in a single binary. Since its 2019 release, Trivy has grown to over 23,000 GitHub stars and is embedded as the default scanner in GitHub's Dependabot alerts pipeline for container images, as well as in tools like Harbor and GitLab's container scanning feature. Its strengths are real: a local vulnerability database cached for offline scans, sub-minute scan times, and broad OS support (Alpine, Debian, Ubuntu, RHEL, Amazon Linux, and more). Where it and comparable open-source scanners (Grype, Clair, Docker Scout) tend to fall short in production environments is prioritization and workflow integration at scale: they report every matched CVE with limited reachability analysis, don't natively correlate findings across an image's full lifecycle (build → registry → runtime), and require teams to build their own policy layer, ticketing integration, and drift tracking on top. For a five-person startup running Trivy in CI, that's a reasonable tradeoff. For a platform team managing 2,000+ images across multiple registries, the raw CVE list becomes a triage bottleneck rather than an answer — one enterprise customer we've worked with was seeing over 14,000 open findings across their registry before any prioritization was applied, most a duplicate of the same base-image CVE.
When Should You Scan — Build Time, Registry, or Runtime?
The most effective programs scan at all three stages, because each catches a different failure mode. Build-time scanning (in CI, before an image is pushed) catches issues early and cheaply — fixing a vulnerable base image at the Dockerfile stage costs a rebuild; fixing it after deployment costs an incident. Registry scanning (continuously re-scanning stored images) matters because CVE databases update daily — an image that was clean on the day it was pushed can become vulnerable a week later when a new CVE is disclosed against a package it already contains, with no code change on your end. Gartner has noted that the average image sits in a registry for 30-90 days before deployment, which is more than enough time for new CVEs to accumulate against it unnoticed. Runtime scanning closes the loop by checking what's actually running versus what was scanned, catching drift from manual patches, sidecar injections, or images pulled from unscanned sources. Skipping any one of these stages creates a blind spot: build-only scanning misses newly disclosed CVEs on old images; registry-only scanning misses fast-moving CI pipelines; runtime-only scanning finds problems only after they're already live.
How Safeguard Helps
Safeguard is built for the gap that shows up once container scanning moves from "does it work" to "does it scale." Instead of treating every matched CVE as equally urgent, Safeguard correlates scan results with reachability and exploitability signals — including whether a vulnerable package is actually loaded at runtime and whether a public exploit exists — so a security team looking at a backlog isn't choosing between fixing 14,000 findings or fixing none. Safeguard ingests SBOMs and scan output from tools you already run, including Trivy, so you don't have to rip out an existing pipeline to get better prioritization; it layers policy enforcement, deduplication across shared base-image layers, and registry drift monitoring on top. It also extends coverage beyond version-matched CVEs to the class of supply chain issues that traditional scanners structurally miss: build provenance verification, dependency confusion detection, and monitoring for anomalous package behavior — the same category of threat the xz-utils backdoor represented. For compliance-driven teams, Safeguard maps scan findings directly to SOC 2 and audit evidence requirements, turning scan output into something an auditor can actually consume rather than a raw JSON export. The goal isn't to replace the scanning step — Trivy and its peers do that well — it's to make the results of scanning actually actionable at the scale modern container fleets operate at.