Defensive Security

Container Image Security: Scanning Is Not Enough

Container image scanning has become a standard pipeline step, and that is progress. But a passing scan is frequently mistaken for a secure image. Scanners compare installed package versions against vulnerability databases — genuinely useful, and blind to configuration, embedded secrets, provenance and everything that happens after the image is built.

Container Image Security: Scanning Is Not Enough

What scanners see and miss

A scanner enumerates packages in the image and matches them against known vulnerability data. That catches outdated system libraries and dependencies, which is worth doing on every build.

  • It misses configuration — running as root, unnecessary capabilities, or a writable filesystem are not package vulnerabilities.
  • It misses secrets — an API key baked into a layer is not a CVE, and remains recoverable from image history even if a later layer deletes the file.
  • It misses provenance — whether the image came from where you think, built from the source you think.
  • It misses application logic — your own code's vulnerabilities are not in any package database.
  • It misses runtime drift — what the container does once running, including anything installed after start.
  • It over-reports — many flagged vulnerabilities sit in packages the application never invokes, producing noise that trains teams to ignore results.

Build smaller and cleaner

  1. Use minimal base images. Fewer packages means a smaller attack surface and dramatically fewer findings to triage.
  2. Use multi-stage builds so compilers, package managers and build-time credentials never reach the final image.
  3. Pin base images by digest rather than a floating tag, so builds are reproducible and cannot silently change.
  4. Rebuild regularly. An image built once and deployed for a year accumulates every vulnerability disclosed in the meantime.
  5. Never place secrets in build arguments or layers — use build-time secret mounts or inject at runtime.
  6. Run as a non-root user and declare it in the image rather than relying on the orchestrator to override.
  7. Remove package managers and shells from production images where practical, which limits what an attacker can do after code execution.
Smaller base images mean less to patch
Smaller base images mean less to patch

Provenance and the supply chain

The harder question is not whether the image contains known vulnerabilities but whether it is the image you intended to run at all.

A generated software bill of materials records what is actually inside; signing establishes that the image came from your pipeline; and admission control enforces that only signed images from trusted registries can run. Without those, an attacker who compromises a registry or a build step can introduce a malicious image that passes every vulnerability scan cleanly, because nothing in it is a known CVE.

Prioritising findings sensibly

Treating every reported vulnerability as equally urgent guarantees the list is ignored. Severity from the scanner is a starting point, not a decision.

A high-severity vulnerability in a package the application never calls, on a workload with no network exposure, matters far less than a medium-severity issue in an internet-facing component. Reachability, exposure and whether a fix exists all belong in the triage. Publicly maintained exploited-vulnerability catalogues are useful here: known exploitation is a much stronger prioritisation signal than a score alone.

Provenance decides whether you can trust what you run
Provenance decides whether you can trust what you run

Runtime still matters

Everything above concerns the image. Once running, the container becomes a live workload that can be attacked through the application it hosts.

Runtime controls therefore remain necessary: restricting what the container may do, monitoring for unexpected process execution or outbound connections, and ensuring a compromised container cannot reach the host or the wider cluster.

Related from TechBiz Security

Sources & further reading

Frequently asked questions

Is a clean image scan enough?
No. Scanners check installed packages against known vulnerability data. They do not assess configuration, embedded secrets, image provenance, your own application code, or runtime behaviour — all of which need separate controls.
Why pin base images by digest instead of a tag?
Tags are mutable, so the same tag can point to different content over time and builds become non-reproducible. Pinning by digest guarantees you build on exactly the content you reviewed, with updates made deliberately.
Are secrets deleted in a later layer safe?
No. Image layers are additive and retained, so a secret added in one layer remains recoverable from image history even if a subsequent layer removes the file. Secrets must never enter a layer in the first place.
How should we prioritise scanner findings?
Combine severity with reachability, exposure and fix availability. A vulnerability in a package the application never calls on an internal workload is less urgent than a moderate issue in an internet-facing component, and known-exploited status is a strong signal to act.

Related reading

0 comments

Leave a comment

Comments are moderated before appearing.