Safeguard
Container Security

What is Container Scanning

Container scanning finds known CVEs, secrets, and misconfigurations in image layers before deployment. Here's how it works and where it falls short.

Vikram Iyer
Cloud Security Engineer
Updated 7 min read

Container scanning is the automated process of inspecting a container image's layers, packages, and metadata to find known vulnerabilities, misconfigurations, and exposed secrets before that image reaches production. A scanner unpacks the image filesystem, builds a manifest of every OS package and language dependency it finds (from Alpine's apk database to a Python requirements.txt frozen at build time), and checks each entry against vulnerability feeds like the National Vulnerability Database (NVD), OSV, and vendor-specific advisories. The output is a list of CVEs, severity scores, and — in mature tools — whether the vulnerable code path is actually reachable at runtime. Teams run this at build time in CI, at rest in a registry, and sometimes on running clusters. It matters because a single base image, like the python:3.9 tag pulled from Docker Hub, can ship with 100+ known CVEs before you've added a single line of application code.

What is container scanning?

Container scanning is static and metadata analysis of a container image to identify known-vulnerable packages, hardcoded secrets, and configuration weaknesses without executing the container. It works by extracting each layer of the OCI image (the format both Docker and Kubernetes use), cataloging installed packages via tools like Syft, and cross-referencing package names and versions against vulnerability databases. This is distinct from scanning source code (SAST) or scanning infrastructure-as-code (IaC scanning) — container scanning specifically targets the built artifact, the thing that actually runs. Open-source scanners like Trivy (from Aqua Security) and Grype (from Anchore) popularized this as a CI step starting around 2019, and it's now table stakes in any pipeline that ships to Kubernetes, ECS, or a serverless container runtime.

How does container scanning actually work?

Container scanning works in three stages: unpack, catalog, and match. First, the scanner pulls the image and extracts its layers — a typical multi-stage Docker build might have 8-15 layers, each potentially reintroducing packages removed in a later stage. Second, it builds a Software Bill of Materials (SBOM), a structured inventory (usually in CycloneDX or SPDX format) listing every OS package, language library, and binary it detected, down to the exact version string. Third, it matches that inventory against vulnerability data sources — NVD's CVE feed, the GitHub Advisory Database, OSV.dev, and distro-specific trackers like Debian's security tracker — and reports every match with a CVSS score. Advanced scanners add a fourth stage: reachability analysis, which checks whether the vulnerable function in a flagged package is actually called by your application code, since most CVEs in a typical image are never invoked at runtime.

What vulnerabilities and risks does container scanning catch?

Container scanning primarily catches four categories: known CVEs in OS and application packages, hardcoded secrets baked into layers, insecure Dockerfile configurations, and outdated base images. Some container security scanning tools also perform a form of container malware scanning — checking layers for known malicious binaries or backdoored packages rather than just CVE matches — though this depends on the specific vendor's threat-intel feed and isn't universal across open-source scanners. On the CVE side, a real-world example is the XZ Utils backdoor (CVE-2024-3094), disclosed March 29, 2024, which was injected into liblzma versions 5.6.0 and 5.6.1 — any image built from an affected Debian or Fedora base during that window would have flagged in a package-level scan within hours of the advisory going public. On the secrets side, scanners routinely catch AWS access keys, private SSH keys, and .env files accidentally copied in via a broad COPY . . instruction — a mistake common enough that it's a named check in nearly every open-source scanner's default ruleset. On configuration, scanners flag containers configured to run as root (still the default in many base images), images missing a USER directive, and containers with writable root filesystems.

When in the pipeline should you scan containers?

Container scanning should happen at three points: pre-merge in CI, pre-deploy at the registry, and continuously against images already running in production. Scanning in CI, typically as a step that runs trivy image or an equivalent against the freshly built image before it's pushed, catches problems before they're merged — this is the cheapest point to fix an issue, since the developer who introduced it is still in context. Scanning at the registry (Amazon ECR, Google Artifact Registry, and Docker Hub all support scan-on-push) catches images that bypassed CI, such as ones built manually or pulled from a third-party registry. Continuous scanning matters because the vulnerability database changes daily — an image that was clean on Monday can have a new critical CVE disclosed against one of its packages by Thursday, and only re-scanning already-deployed images catches that drift. Organizations with mature pipelines typically enforce a policy gate at the CI stage (e.g., block merge on any critical/high CVE with a fix available) and use registry and runtime scanning as a safety net.

Why do container scans generate so many false positives?

Container scans generate high false-positive rates because most scanners flag every version match against a CVE database regardless of whether the vulnerable code path is reachable or exploitable in context. A 2023 analysis pattern seen across multiple vendor reports is consistent: a typical enterprise image scan returns hundreds of CVEs, but fewer than 10% involve a package function that the application actually calls. Distro backporting compounds this — Debian and Red Hat frequently patch a CVE by backporting a fix into an older version string, so a scanner doing naive version comparison (rather than checking against the distro's own patch tracking) will flag a package as vulnerable when it's already fixed. This is the core reason security teams report alert fatigue as a top complaint about scanning tools: without reachability analysis or exploit-context prioritization, engineers spend hours triaging CVEs in packages like glibc or openssl that are present in the image but never exercised by the running service.

How is container scanning different from image signing or runtime protection?

Container scanning finds vulnerabilities before deployment, while image signing verifies an image's origin and integrity, and runtime protection monitors behavior after the container is already executing. Signing, using tools like Sigstore's Cosign (a CNCF project that hit widespread adoption after the 2021 SolarWinds and Codecov incidents pushed supply-chain integrity into the spotlight), cryptographically attests that an image came from a trusted build pipeline and hasn't been tampered with in the registry — it says nothing about whether the image contains vulnerable code. Runtime protection — sometimes called container runtime scanning, using tools like Falco — watches for anomalous syscalls or network behavior once the container is live, catching exploitation attempts that scanning couldn't predict, such as a novel zero-day. The three controls are complementary and map to different points in the software supply chain: scanning at build time, signing at distribution time, and runtime protection at execution time. Skipping any one leaves a gap — a signed image can still be full of known CVEs, and a scanned image can still be swapped for a malicious one in transit without signing.

How Safeguard Helps

Safeguard turns container scanning from a CVE-count exercise into a prioritized, actionable workflow. Reachability analysis traces whether a flagged vulnerability sits on a code path your application actually executes, so teams stop triaging CVEs in dead code and focus on the handful that are genuinely exploitable. Griffin AI, Safeguard's reasoning engine, correlates scan findings across SBOMs, source code, and runtime signals to explain why a given CVE matters in your specific deployment, not just its CVSS score. Safeguard generates SBOMs at build time and ingests existing ones from upstream vendors, giving you a single inventory across every image in your registry. When a fix is available, Safeguard opens an auto-fix pull request with the dependency bump and a summary of what changed, cutting remediation time from a ticket in a backlog to a mergeable diff.

Never miss an update

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