
The Measurement Trap
Most container security programs are measuring the wrong things.
Teams count CVEs. They track image size. They celebrate when a base image update drops critical vulnerabilities from 47 to 12. But none of these tells you whether your running container is actually harder to exploit.
Attack surface reduction is not about improving metrics. It is about eliminating the ways an attacker can enter, move, escalate, and persist, and proving those paths no longer exist.
The shift is simple:
From inventory to exploitability.
From what’s installed to what actually executes.
And that shift starts at the image.
Why Traditional Metrics Fall Short
Most container security metrics share a common limitation: they measure what is present, not what is exploitable.
They provide an accurate inventory of the image, but very little insight into how that image behaves at runtime. As a result, they often create a false sense of progress.
Consider some of the most widely used metrics:
- Total CVE count reflects every known vulnerability across all installed packages, but does not indicate whether those packages are ever used.
- Critical or high CVEs highlight severity, but not reachability. A critical vulnerability in a dormant library is prioritized the same as one in an actively executed code path.
- Image size signals footprint, but not execution. A smaller image can still contain unnecessary binaries that are never used.
- Base image freshness indicates how recently the OS was updated but says nothing about what was added during the build.
- SBOM completeness ensures inventory coverage, but does not capture runtime behavior, provenance integrity, or post-build drift.
The pattern is consistent. These metrics describe what exists in the image, but not what an attacker can actually use.
This becomes clear in real workloads.
A typical container may include hundreds of packages, while only a fraction participate in execution at runtime. The rest remain inert, yet they are still scanned, counted, and prioritized equally.
This creates a prioritization problem. Vulnerabilities in inactive components compete for attention with vulnerabilities in active code paths. Teams spend time triaging issues that have no realistic exploitation path while missing the ones that matter.
Attack surface reduction is about closing this gap.
It requires a shift:
- from installed packages to reachable packages
- from granted privileges to exercised privileges
- from theoretical exposure to observable behavior
Until that shift happens, improvements in metrics do not necessarily translate to improvements in security.
What Actually Defines Attack Surface
Attack surface is defined by what can actually be used, not what merely exists.
This includes runtime execution paths, privilege escalation opportunities such as setuid or setgid binaries, network exposure through open ports and outbound connectivity, embedded secrets, and writable filesystem areas that allow persistence. It also includes whether every component in the image has verifiable build provenance and whether granted Linux capabilities are actually exercised.
These risks do not exist in isolation. They compound.
A container with excess capabilities, a writable filesystem, and unrestricted egress is not facing three separate issues. It has a single exploitable chain that enables escalation, persistence, and data exfiltration.
Best Practices for Reducing Container Attack Surface
The most meaningful reductions in attack surface do not happen at runtime. They are designed into the image itself.
Each of the practices below removes a class of exploitable paths and can be measured.
Minimize the Runtime Image
The highest-leverage step is reducing what exists in the runtime environment.
Standard base images include shells, package managers, and system utilities that most applications never use. These components expand the attack surface without contributing to execution.
Using distroless or hardened container images removes this excess by design. Combined with multi-stage builds, where only compiled artifacts are carried into the final image, this typically reduces hundreds of packages to a minimal set required for execution.
This is not just a size optimization. It is a reduction in reachable attack surface.
Eliminate Build-Time Residue
Build environments introduce tools and dependencies that should never exist in production.
Compilers, package managers, and test frameworks expand the number of binaries and libraries present in the image. If carried into runtime, they create unnecessary execution paths.
Multi-stage builds ensure that only runtime artifacts are preserved. Comparing the build-stage footprint with the final image provides a direct measure of attack surface removed.
Build-stage images themselves should also be governed or removed. Leaving them accessible introduces unnecessary exposure.
Enforce Least Privilege
Containers often run with more privilege than required.
Linux capabilities enable operations such as raw socket access or filesystem manipulation that most applications do not need. Privilege should be treated as opt-in: drop all capabilities and add back only what is explicitly required.
Running as a non-root user further reduces the impact of compromise by limiting access to the system.
The measurable outcome is the gap between granted and exercised privilege. In a well-constrained container, that gap should not exist.
Constrain the Filesystem
A writable filesystem enables persistence.
If an attacker can modify the filesystem, they can inject scripts, alter binaries, or establish footholds that persist beyond the initial exploit.
A read-only root filesystem removes this class of risk. Any required write access should be explicitly scoped.
This transforms the container into a controlled execution unit rather than a mutable environment.
Restrict Network Exposure
Network access defines both ingress and egress.
Open ports increase exposure. Unrestricted outbound connectivity enables data exfiltration and lateral movement.
Attack surface reduction requires defining expected communication and enforcing it through restricted ports, controlled bindings, and egress policies.
Predictability is key. Unexpected network behavior should always be treated as a signal.
Remove Secrets from the Image
Secrets embedded in image layers remain recoverable even if deleted later.
This creates a persistent risk.
Secrets should be injected at runtime using controlled mechanisms. Reducing secret presence in images directly reduces exposure.
Remove Package Managers and Installation Paths
Package managers in runtime images introduce a modification vector.
If an attacker gains access, they can install additional tools or expand capabilities.
Removing these components ensures the container remains immutable after deployment.
Enforce Supply Chain Integrity
Attack surface is not just about what is present, but where it originated.
Every component should have verifiable provenance. Signed, verified images, build attestations, and build-attached SBOMs ensure that what runs is trusted.
This transforms the container into a verifiable unit rather than an opaque artifact.
The Role of SBOM: Evidence, Not Just Inventory
An SBOM is often treated as a compliance artifact but as discussed in our previous blog, SBOMs alone do not establish container trust.
Its real value is as a baseline for measurement.
A signed, build-attached SBOM provides a verified inventory of what was included at build time. It enables detection of runtime drift, correlation of execution behavior, and traceability of components.
Without reachability and provenance context, an SBOM is just a list. With context, it becomes a foundation for trust.
Continuous Measurement, Not One-Time Scans
Attack surface evolves with every rebuild, dependency update, and configuration change.
A meaningful approach spans the lifecycle. At build time, the image establishes a baseline. At admission, only verified artifacts are allowed. At runtime, behavior is continuously measured against that baseline.
The feedback loop ensures that issues are traced back to their source and resolved systematically.
Metrics That Actually Matter
The most useful metrics reflect exploitability:
- Reachable package ratio: executed vs installed packages (target <20%)
- Provenance coverage: components with verified origin (target near 100%)
- Capability excess ratio: unused vs granted capabilities (target 0)
- Runtime drift: deviation from build-time SBOM (target 0)
- Reachable critical CVEs: vulnerabilities in active execution paths
Reducing reachable critical vulnerabilities from 23 to 2 is a real reduction in risk, even if total CVE counts increase.
Container Attack Surface Maturity Model
A maturity model helps teams understand progress:
L0 — Blind
No SBOM, no visibility.
L1 — Inventory
Package lists and CVE counts.
L2 — Verified Inventory
Signed SBOM and initial provenance.
L3 — Provenance-Aware
Trusted and verifiable build chain.
L4 — Runtime-Closed
Continuous runtime profiling, drift detection, and full correlation.
Most teams believe they are at L2 or L3. Many are still at L1. The difference lies in whether runtime behavior can be proven and traced.
Conclusion: Start at the Image
Attack surface reduction is a measurement problem before it is a remediation problem.
If you cannot determine what executes, what is reachable, and what is trusted, you cannot determine whether risk is actually being reduced.
The most effective control point is the image itself.
A minimal, verified image with a reduced package footprint, constrained privileges, and enforced provenance shrinks the attack surface before the container ever runs. You can explore and use production-ready hardened images directly through our image portal.
Everything downstream becomes easier.
The goal is not fewer CVEs.
The goal is a container that does only what it should, contains only what is necessary, and is provably nothing more.
.webp)
.png)
.webp)
.webp)
.webp)