Distroless Container Images and Scanning: Fewer CVEs But Not Zero

Distroless Container Images and Scanning: Fewer CVEs But Not Zero

Distroless images are the correct response to the observation that most container images contain far more software than their applications need. Remove the shell. Remove the package manager. Remove the system utilities. Keep only the language runtime the application requires. The result is a smaller image with a smaller CVE count.

Teams that have adopted distroless often encounter an unexpected experience: they scan their distroless image expecting minimal CVE findings and find 20, 40, or 80 findings. “I thought distroless was supposed to fix this.”

Distroless reduces CVE exposure substantially. It does not eliminate it. Understanding where the remaining CVEs come from — and what to do about them — is the practical next step for teams that have already adopted distroless.


Where CVEs Come From in Distroless Images?

The language runtime itself: Google’s gcr.io/distroless/python3 includes Python. Python has CVEs. The Python language runtime includes the standard library, which includes modules that have accumulated CVE histories. A distroless Python image is free of shell utilities and system packages, but it is not free of Python interpreter CVEs.

C library and system library dependencies: Distroless images include glibc or musl as a runtime dependency. These libraries have CVE histories. A distroless image that includes libssl (for HTTPS support) includes any CVEs present in that libssl version.

Application dependencies added on top: Distroless is a base image. The application layers added on top are not distroless. A Python application that installs 40 packages adds those packages’ CVEs to the distroless base’s CVE count. The distroless base has 30 CVEs; the application layers add 60 more; the total is 90.

Language runtime components not used by the application: The Python standard library includes modules for email parsing, XML processing, audio encoding, cryptographic operations, and many other domains. A web API application uses a small subset of these. The rest are present in the image but unused by the application. They carry CVEs without providing application value.


Hardened Container Images vs. Standard Distroless

Standard distroless addresses the base image layer — it removes OS utilities that are not needed. It does not address:

  • Unused language runtime modules within the included Python/Java/Node runtime
  • Application dependencies that are installed but not actually imported during execution
  • Transitive dependencies of application dependencies that are never loaded

Runtime profiling applied to distroless images captures which parts of the runtime are actually executed and which application dependencies are actually imported during representative execution. Components with zero execution evidence — including portions of the language runtime — are candidates for removal.

The result is an image that goes further than distroless: not just “no shell utilities” but “no unused language runtime components either.”

The practical difference:

  • Standard distroless Python: ~80 packages, ~60 CVEs
  • Profiling-based hardened distroless Python: ~30-40 packages, ~15-25 CVEs

The additional reduction comes from removing unused standard library modules and unused transitive dependencies.


Scanner Behavior on Distroless Images

Container scanning tools behave differently on distroless images than on standard images:

OS package detection: Standard scanners detect OS packages via package manager databases (dpkg, rpm, apk). Distroless images have no package manager database. Some scanners fall back to filesystem scanning to detect packages without a database; others report no findings at the OS level and miss CVEs in libraries present without package manager records.

File-based detection: Scanners that use file checksums or binary signatures can detect CVEs in libraries present in distroless images without package manager databases. The detection accuracy depends on the scanner’s library detection coverage.

Container image tool that uses comprehensive file-based scanning in addition to package database scanning provides more complete coverage of distroless images than scanners that rely primarily on package database lookups.

False positives on stripped packages: Distroless images sometimes include stripped versions of libraries where only specific files are present. Scanners that match CVEs to package names may incorrectly report CVEs for packages where only a subset of files is present. These false positives require manual investigation to verify.


Frequently Asked Questions

Do distroless container images eliminate CVEs entirely?

Distroless images significantly reduce CVE exposure by removing shells, package managers, and system utilities, but they do not eliminate CVEs entirely. The language runtime itself, C library dependencies, and application packages added on top of the distroless base all carry their own CVE histories. A distroless Python image is still subject to CVEs in the Python interpreter and any application dependencies layered on top.

How does runtime profiling further reduce CVEs in distroless container images?

Runtime profiling goes beyond what standard distroless images provide by capturing which parts of the language runtime are actually executed during representative load. Unused standard library modules and unimported transitive dependencies can be removed based on this execution evidence. In practice, profiling-based hardening on a distroless Python image can reduce CVE counts from roughly 60 down to 15-25 by removing unused runtime components.

How do container scanning tools handle distroless images without a package manager database?

Scanners that rely solely on Linux package manager databases (dpkg, rpm, apk) may miss CVEs in distroless images because distroless images have no package manager database. File-based detection using binary checksums or file signatures provides more complete coverage, identifying CVEs in libraries present in the image regardless of how they were installed. Teams using distroless should verify their scanner uses file-based detection in addition to package database lookups.

What is the practical next step after adopting distroless container images?

After adopting distroless, the practical next step is applying runtime-profiling-based hardening to remove unused language runtime components and unimported application dependencies. This produces an image that goes further than standard distroless — not just removing OS utilities, but also removing unused standard library modules and zero-execution transitive dependencies. The result is a substantially lower CVE count than standard distroless achieves alone.


The Practical Guidance for Distroless Users

If you have adopted distroless and are seeing scanner findings:

Verify the findings are real: Check scanner false positive rates on distroless images. Some findings in distroless environments are false positives due to incomplete distroless package detection. Verify that reported packages are actually present in the image before prioritizing remediation.

Profile the runtime usage: For CVEs in the language runtime or standard library, runtime profiling identifies which parts of the runtime your application actually uses. Unused modules that carry CVEs can be removed through custom image construction.

Address application dependency CVEs: Application dependencies layered on distroless carry real CVEs. Use software composition analysis to identify which are in your direct and transitive dependencies, and address CVEs in used packages through version upgrades.

Consider curated near-zero-CVE variants: Pre-hardened distroless variants that have been profiled against common usage patterns and further minimized beyond the standard distroless images are available for common language runtimes. These go further than standard distroless while preserving the distroless approach.

Distroless is the right direction. The practical state of the art is to apply runtime-profiling-based hardening on top of distroless to reach the minimal achievable CVE count for your specific application. That minimum is significantly lower than what standard distroless provides.Distroless images are the correct response to the observation that most container images contain far more software than their applications need. Remove the shell. Remove the package manager. Remove the system utilities. Keep only the language runtime the application requires. The result is a smaller image with a smaller CVE count.

Teams that have adopted distroless often encounter an unexpected experience: they scan their distroless image expecting minimal CVE findings and find 20, 40, or 80 findings. “I thought distroless was supposed to fix this.”

Distroless reduces CVE exposure substantially. It does not eliminate it. Understanding where the remaining CVEs come from — and what to do about them — is the practical next step for teams that have already adopted distroless.


Where CVEs Come From in Distroless Images?

The language runtime itself: Google’s gcr.io/distroless/python3 includes Python. Python has CVEs. The Python language runtime includes the standard library, which includes modules that have accumulated CVE histories. A distroless Python image is free of shell utilities and system packages, but it is not free of Python interpreter CVEs.

C library and system library dependencies: Distroless images include glibc or musl as a runtime dependency. These libraries have CVE histories. A distroless image that includes libssl (for HTTPS support) includes any CVEs present in that libssl version.

Application dependencies added on top: Distroless is a base image. The application layers added on top are not distroless. A Python application that installs 40 packages adds those packages’ CVEs to the distroless base’s CVE count. The distroless base has 30 CVEs; the application layers add 60 more; the total is 90.

Language runtime components not used by the application: The Python standard library includes modules for email parsing, XML processing, audio encoding, cryptographic operations, and many other domains. A web API application uses a small subset of these. The rest are present in the image but unused by the application. They carry CVEs without providing application value.


Hardened Container Images vs. Standard Distroless

Standard distroless addresses the base image layer — it removes OS utilities that are not needed. It does not address:

  • Unused language runtime modules within the included Python/Java/Node runtime
  • Application dependencies that are installed but not actually imported during execution
  • Transitive dependencies of application dependencies that are never loaded

Runtime profiling applied to distroless images captures which parts of the runtime are actually executed and which application dependencies are actually imported during representative execution. Components with zero execution evidence — including portions of the language runtime — are candidates for removal.

The result is an image that goes further than distroless: not just “no shell utilities” but “no unused language runtime components either.”

The practical difference:

  • Standard distroless Python: ~80 packages, ~60 CVEs
  • Profiling-based hardened distroless Python: ~30-40 packages, ~15-25 CVEs

The additional reduction comes from removing unused standard library modules and unused transitive dependencies.


Scanner Behavior on Distroless Images

Container scanning tools behave differently on distroless images than on standard images:

OS package detection: Standard scanners detect OS packages via package manager databases (dpkg, rpm, apk). Distroless images have no package manager database. Some scanners fall back to filesystem scanning to detect packages without a database; others report no findings at the OS level and miss CVEs in libraries present without package manager records.

File-based detection: Scanners that use file checksums or binary signatures can detect CVEs in libraries present in distroless images without package manager databases. The detection accuracy depends on the scanner’s library detection coverage.

Container image tool that uses comprehensive file-based scanning in addition to package database scanning provides more complete coverage of distroless images than scanners that rely primarily on package database lookups.

False positives on stripped packages: Distroless images sometimes include stripped versions of libraries where only specific files are present. Scanners that match CVEs to package names may incorrectly report CVEs for packages where only a subset of files is present. These false positives require manual investigation to verify.


Frequently Asked Questions

Do distroless container images eliminate CVEs entirely?

Distroless images significantly reduce CVE exposure by removing shells, package managers, and system utilities, but they do not eliminate CVEs entirely. The language runtime itself, C library dependencies, and application packages added on top of the distroless base all carry their own CVE histories. A distroless Python image is still subject to CVEs in the Python interpreter and any application dependencies layered on top.

How does runtime profiling further reduce CVEs in distroless container images?

Runtime profiling goes beyond what standard distroless images provide by capturing which parts of the language runtime are actually executed during representative load. Unused standard library modules and unimported transitive dependencies can be removed based on this execution evidence. In practice, profiling-based hardening on a distroless Python image can reduce CVE counts from roughly 60 down to 15-25 by removing unused runtime components.

How do container scanning tools handle distroless images without a package manager database?

Scanners that rely solely on Linux package manager databases (dpkg, rpm, apk) may miss CVEs in distroless images because distroless images have no package manager database. File-based detection using binary checksums or file signatures provides more complete coverage, identifying CVEs in libraries present in the image regardless of how they were installed. Teams using distroless should verify their scanner uses file-based detection in addition to package database lookups.

What is the practical next step after adopting distroless container images?

After adopting distroless, the practical next step is applying runtime-profiling-based hardening to remove unused language runtime components and unimported application dependencies. This produces an image that goes further than standard distroless — not just removing OS utilities, but also removing unused standard library modules and zero-execution transitive dependencies. The result is a substantially lower CVE count than standard distroless achieves alone.


The Practical Guidance for Distroless Users

If you have adopted distroless and are seeing scanner findings:

Verify the findings are real: Check scanner false positive rates on distroless images. Some findings in distroless environments are false positives due to incomplete distroless package detection. Verify that reported packages are actually present in the image before prioritizing remediation.

Profile the runtime usage: For CVEs in the language runtime or standard library, runtime profiling identifies which parts of the runtime your application actually uses. Unused modules that carry CVEs can be removed through custom image construction.

Address application dependency CVEs: Application dependencies layered on distroless carry real CVEs. Use software composition analysis to identify which are in your direct and transitive dependencies, and address CVEs in used packages through version upgrades.

Consider curated near-zero-CVE variants: Pre-hardened distroless variants that have been profiled against common usage patterns and further minimized beyond the standard distroless images are available for common language runtimes. These go further than standard distroless while preserving the distroless approach.

Distroless is the right direction. The practical state of the art is to apply runtime-profiling-based hardening on top of distroless to reach the minimal achievable CVE count for your specific application. That minimum is significantly lower than what standard distroless provides.