Container Image Security: Scanning Before You Ship
Practical approaches to container image security scanning that catch vulnerabilities before they reach production.
February 22, 2026 · 6 min · 1223 words · Rob Washington
Table of Contents
Every container image you deploy is a collection of dependencies you didn’t write. Some of those dependencies have known vulnerabilities. The question isn’t whether your images have CVEs — it’s whether you know about them before attackers do.
FROM gcr.io/distroless/python3-debian12COPY --from=builder /app /appCMD["/app/main.py"]
Distroless images contain only your application and its runtime dependencies. No shell, no package manager, no coreutils. An attacker who gets code execution can’t curl their malware because curl doesn’t exist.
# OPA/Conftest policypackage maindeny[msg] {input.image.base == "ubuntu:latest"msg := "Don't use 'latest' tag for base images"}deny[msg] {not startswith(input.image.base, "gcr.io/")not startswith(input.image.base, "registry.company.com/")msg := sprintf("Untrusted base image: %s", [input.image.base])}deny[msg] {input.user == "root"msg := "Containers must not run as root"}
When a new critical CVE is published for a package in your production image, you’ll know within 6 hours — not when a security researcher tweets about it.
Not every CVE affects you. A vulnerability in libxml2 doesn’t matter if your code never parses XML.
1
2
3
4
5
6
# .trivyignore# CVE-2023-XXXXX: We don't use the affected functionCVE-2023-XXXXX# Suppress until we can upgrade (time-limited)CVE-2024-YYYYY exp:2024-03-01
Document why you’re ignoring each CVE. Review suppressions regularly.
-- Average time from CVE publish to patch in production
SELECTAVG(patched_at-cve_published_at)asmean_time_to_patchFROMvulnerability_patchesWHEREseverity='CRITICAL'ANDpatched_at>NOW()-INTERVAL'90 days';-- Images in production with unpatched criticals
SELECTCOUNT(DISTINCTimage)FROMrunning_containerscJOINvulnerability_scansvONc.image=v.imageWHEREv.critical_count>0;
If your mean time to patch is measured in weeks, you have a process problem. If it’s measured in months, you have a culture problem.
Use slim base images — One line change in Dockerfile
Run as non-root — Add USER nonroot to Dockerfile
Pin your base image tags — python:3.11.7, not python:3.11
That’s 30 minutes of work for 80% of the security benefit. Everything else is refinement.
Container security isn’t about achieving zero CVEs — that’s impossible. It’s about knowing what vulnerabilities exist in your stack, understanding which ones are exploitable, and fixing the critical ones before someone else finds them.
📬 Get the Newsletter
Weekly insights on DevOps, automation, and CLI mastery. No spam, unsubscribe anytime.