Technology

Hardening Container Images: A Practical Pipeline From Base Image to Signed Release

Most container risk is decided before a container ever runs. The base image you choose, the packages you add, and whether anyone rebuilds the image when new CVEs land determine the attack surface you ship.

This guide covers docker image security end to end: choosing minimal base images, writing safer Dockerfiles, scanning in CI, generating SBOMs, signing images and enforcing policy at deploy time.

Each section includes commands you can adapt. Tools named are common open-source options; equivalent commercial products work the same way.

Why docker image security starts with the base image

A general-purpose base image brings a full userland: shells, package managers, compilers and hundreds of libraries your application never calls.

Every one of them can carry CVEs, and every one is a tool an attacker can use after initial access.

The data supports caution. Sysdig’s 2023 Cloud-Native Security and Usage Report found that 87% of container images had high or critical vulnerabilities, but only 15% of fixable critical and high vulnerabilities were in packages actually loaded at runtime (2023).

That gap is the argument for smaller images: if a package is not present, its CVEs cannot be exploited and do not need triage.

Leaving known weaknesses unresolved also has a compounding cost. Old images drift further from patched upstream versions, and a rebuild that would have been trivial becomes a breaking upgrade.

NIST’s SP 800-190 Application Container Security Guide lists image vulnerabilities, embedded secrets and use of untrusted images among the primary container risks.

How compromised images reach production

Outdated packages are only one path. Public registries have also been used to deliver malicious content directly:

In ATT&CK terms these map to T1195.002 (Compromise Software Supply Chain) and T1610 (Deploy Container), with T1611 (Escape to Host) as the follow-on risk when a container runs privileged.

Kernel and runtime flaws remain relevant too; a container breakout vulnerability turns any foothold in an image into host access.

Choosing a minimal base image

Base typeExamplesStrengthsTrade-offs
Full distributionubuntu, debianFamiliar tooling, easy debuggingLargest attack surface and CVE count
Slim variantsdebian-slim, python:3.x-slimFewer packages, same libcStill includes shell and package manager
AlpinealpineVery smallmusl libc can cause compatibility issues
Distrolessgcr.io/distroless/static, /baseNo shell or package managerDebugging needs ephemeral debug containers
Hardened low-CVE imagesVendor-maintained minimal imagesRebuilt continuously, often with SLAsVendor dependency, possible cost

Hardened image providers rebuild packages from source to keep CVE counts down; Minimus describes this approach to near zero CVE images.

Whichever route you take, the principle matches CIS Controls v8 Control 2 (inventory and control of software assets) and Control 7 (continuous vulnerability management): ship only what you need and know exactly what that is.

Writing a safer Dockerfile

A multi-stage build keeps compilers and build tools out of the final image. The example below builds a Go service and ships it on a distroless base as a non-root user.

# syntax=docker/dockerfile:1
FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags=”-s -w” -o /out/app ./cmd/app

# Pin by digest, not just tag
FROM gcr.io/distroless/static-debian12@sha256:<digest>
COPY –from=build /out/app /app
USER 65532:65532
ENTRYPOINT [“/app”]

Dockerfile rules worth enforcing

  1. Pin base images by digest so builds are reproducible, and use a bot such as Renovate or Dependabot to propose digest updates.
  2. Run as non-root with an explicit numeric USER.
  3. Never bake secrets into layers. Use BuildKit secret mounts (RUN –mount=type=secret,id=npmrc …) instead of COPY or ARG.
  4. Use a .dockerignore to keep .git, .env and local credentials out of the build context.
  5. Rebuild on a schedule, not only on code changes, so upstream patches reach you.

Container vulnerability scanning in CI

Scan every image at build time, fail the pipeline on findings that matter, and rescan stored images daily because new CVEs are published against old packages. Trivy and Grype are widely used open-source scanners.

# Scan a local image and fail on fixable high/critical CVEs
trivy image –severity HIGH,CRITICAL –ignore-unfixed –exit-code 1 myapp:1.4.2

# Equivalent with Grype
grype myapp:1.4.2 –fail-on high –only-fixed

# Scan the Dockerfile and IaC for misconfigurations
trivy config –exit-code 1 ./

Example GitHub Actions job

The workflow below is illustrative. Pin third-party actions to full commit SHAs, not tags; security tooling itself has been targeted in supply chain attacks.

jobs:
  build-scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write      # for keyless signing
      packages: write
    steps:
      – uses: actions/checkout@<commit-sha>
      – name: Build
        run: docker build -t ghcr.io/org/myapp:${{ github.sha }} .
      – name: Scan
        run: trivy image –severity HIGH,CRITICAL –ignore-unfixed –exit-code 1 ghcr.io/org/myapp:${{ github.sha }}
      – name: SBOM
        run: syft ghcr.io/org/myapp:${{ github.sha }} -o spdx-json > sbom.spdx.json
      – name: Push and sign
        run: |
          docker push ghcr.io/org/myapp:${{ github.sha }}
          cosign sign –yes ghcr.io/org/myapp@$(docker inspect –format='{{index .RepoDigests 0}}’ ghcr.io/org/myapp:${{ github.sha }} | cut -d@ -f2)
          cosign attest –yes –type spdxjson –predicate sbom.spdx.json ghcr.io/org/myapp:${{ github.sha }}

Triage rules that keep the gate usable

  • Block on fixable critical and high CVEs; report the rest.
  • Prioritize findings listed in CISA’s Known Exploited Vulnerabilities catalog regardless of CVSS.
  • Record accepted risks in a VEX document or scanner ignore file with an owner and an expiry date.

For a comparison of scanners and runtime tools, see the best container security tools roundup.

Generating and using SBOMs

A software bill of materials lists every package and version in an image. When the next XZ-style incident hits, an SBOM index answers “where do we run this?” in minutes instead of days.

CISA’s 2025 Minimum Elements for a Software Bill of Materials sets out the fields an SBOM should contain.

# Generate SPDX and CycloneDX SBOMs
syft myapp:1.4.2 -o spdx-json=sbom.spdx.json -o cyclonedx-json=sbom.cdx.json

# Scan an SBOM later without pulling the image
grype sbom:./sbom.cdx.json

Store SBOMs as signed attestations next to the image in the registry, then feed them into a dependency inventory so you can query across all deployed images.

Signing images and enforcing policy at deploy time

Scanning in CI only helps if production refuses images that skipped the pipeline. Sign images with Sigstore cosign, then verify signatures and attestations at admission.

# Verify a keyless signature from a specific CI identity
cosign verify ghcr.io/org/myapp@sha256:<digest> \
  –certificate-identity-regexp “https://github.com/org/myapp/.github/workflows/.*” \
  –certificate-oidc-issuer https://token.actions.githubusercontent.com

In Kubernetes, an admission controller such as Kyverno, OPA Gatekeeper or Sigstore policy-controller can enforce rules like these:

  1. Only images from approved registries, referenced by digest.
  2. Only images signed by the CI identity.
  3. No containers running as root, privileged, or with host namespaces.
  4. Read-only root filesystems where the application allows it.

Registry hygiene matters as well. Restrict who can push, enable immutable tags, and monitor for account compromise; a Docker Hub flaw that let attackers impersonate users and push images shows why signature verification should not rely on registry trust alone.

Keeping deployed images current

A clean image on release day is not a clean image three months later. New CVEs are published against packages that were fine when you built, so the security state of an image changes even if nobody touches it. The fix is a feedback loop rather than a one-time scan.

An operating rhythm that works

  1. Rescan the registry daily. Most registries and scanners can re-evaluate stored images or SBOMs against fresh vulnerability data. Route new critical findings to the owning team, not a shared inbox.
  2. Automate base image updates. Let a dependency bot open pull requests when a pinned base digest changes, and let CI run the full scan and test suite on each one.
  3. Track image age. Report on the age of running images by workload. Anything older than your rebuild policy is a finding in its own right, regardless of current CVE count.
  4. Retire unused images. Delete old tags and untagged manifests from registries so that nobody redeploys a forgotten vulnerable build.
  5. Close the loop with runtime data. Combine scanner output with what actually runs in production, so remediation starts with images that are deployed and internet-facing.

Measure progress with a small set of metrics: mean time to remediate fixable critical CVEs, percentage of running images built in the last 30 days, and percentage of deployments that passed signature verification.

Those three numbers show whether the pipeline is doing its job far better than a raw CVE total.

Key takeaways

  • Docker image security is mostly decided by the base image; smaller images mean fewer CVEs and fewer attacker tools.
  • Use multi-stage builds, digest pinning, non-root users and BuildKit secret mounts.
  • Scan in CI and rescan stored images daily; block on fixable high and critical findings and KEV entries.
  • Generate SBOMs for every image and keep them queryable for incident response.
  • Sign images and enforce signature and policy checks at admission.
  • Pin CI actions and scanners by commit SHA; the build pipeline is part of the supply chain.

FAQ

How do I scan a Docker image for vulnerabilities?

Run an open-source scanner such as Trivy (trivy image name:tag) or Grype (grype name:tag) locally or in CI. Configure it to fail the build on fixable high and critical CVEs.

What is the most secure Docker base image?

There is no single answer, but minimal images such as distroless or vendor-hardened low-CVE images expose the least. Choose the smallest image that runs your application and rebuild it regularly.

What is a distroless image?

It is a container image that contains only your application and its runtime dependencies, without a shell or package manager. This reduces attack surface and limits what an intruder can do inside the container.

Why do I need an SBOM for container images?

An SBOM records every package and version in an image, so you can quickly find affected workloads when a new vulnerability is disclosed and meet customer or regulatory transparency requirements.

How often should Docker images be rebuilt?

Rebuild at least weekly or whenever the base image publishes a security update, and rescan stored images daily against fresh vulnerability data.

Kavichselvan

Kavichselvan is a Cybersecurity Enthusiast and Journalist covering Cyber Attacks, Threats, Breaches, Vulnerabilities and other happenings in the cyber world.

Recent Posts

OpenAI Launches GPT-6 Cyber That Finds 81 Firefox Flaws and Develops 948 Linux Exploits

OpenAI has launched GPT-6 Cyber, a security-focused AI model that found 81 new high-severity Firefox…

3 hours ago

Shopify Mandates IP Allowlisting for Public Apps to Prevent Unauthorized Admin API Access

Shopify is making IP allowlisting mandatory for public apps that call its Admin API, adding…

3 hours ago

Microsoft Paint 0-Click Vulnerability Could Allow Hackers to Take Control of Windows PCs

Microsoft’s Windows Paint vulnerability, CVE-2026-83844, could allow an unauthenticated attacker to execute code over a…

4 hours ago

OpenMatter Network Positions Decentralized Computing as an Alternative to Data Centers for AI

Melbourne, Florida, November 5th, 2026, CyberNewswire OpenMatter Network, a pioneer in decentralized infrastructure for agentic…

12 hours ago

GhostMap Android Flaw Can Trap Phones in Endless Reboot Loops Without Opening an App

A new Android bug named GhostMap can leave a phone stuck in a crash loop…

13 hours ago

Hackers Turn Popular Chinese Keyboard Software Into a Backdoor for Cyberespionage Attacks

A China-aligned hacking group is abusing Sogou Input Method, one of the most popular Chinese…

14 hours ago