Container Security: A Practical Guide to Scanning Docker Images
A container built from a base image pulled six months ago ships every CVE patched in that time - not because anyone wrote vulnerable code, but because nobody rebuilt the image since.
Where the Risk Actually Lives
- The base image itself.
FROM node:18without a specific patch version pulls whatever that tag currently resolves to - which drifts over time, and an unpinned tag can silently start shipping a different (and possibly vulnerable) underlying OS version. - OS packages baked into the layer.A base image's own package manager entries (glibc, openssl, and similar) carry their own CVEs independent of anything your application code does.
- Application dependencies copied into the image- the same dependency-CVE problem any codebase has, just now frozen into an image layer that won't update on its own.
- Secrets baked into layers. An API key set via
ENVor copied in during a build step remains in that layer's history even if a later layer removes the file - anyone with access to the image can extract it.
What Image Scanning Actually Checks
A container scanner inspects the image's layers for known-vulnerable package versions - both OS packages and language-specific dependencies - cross-referenced against CVE databases, the same way dependency scanning works for a codebase, just applied to the built artifact instead of the source.
Practical Fixes
1. Pin base image versions explicitly
Use a specific, verifiable tag (node:18.20.4-slim) rather than a moving target like node:18 or latest, so what you tested is what actually ships.
2. Rebuild on a schedule, not just on code changes
A container that hasn't changed in months still accumulates newly-disclosed CVEs in its frozen base layer - rebuilding periodically (even with no application code changes) picks up upstream security patches.
3. Use minimal base images
A slim or alpine variant ships far fewer packages than a full OS image, which directly shrinks the CVE surface simply by having less installed to be vulnerable in the first place.
4. Never bake secrets into a layer
Use build-time secret mounts (Docker's --secret flag) or inject secrets at runtime instead of ENV/COPYduring the build - both leave the value recoverable from the image's layer history otherwise.
Automate this in your next PR
Run a free repo scan and see outdated dependencies, CVEs, and code quality issues before they ship.
Run a free repo scanRelated reading
Scanverra vs. Snyk
A developer-security platform scanning open-source dependencies, source code, containers, and IaC, priced per contributing developer with a capped free tier.
Scanverra vs. SonarQube (SonarSource)
A static code analysis platform for bugs, vulnerabilities, code smells, and technical debt across 30+ languages, free up to 50k lines of code.