Guide

Secrets in Docker Images: How They Get There and How to Find Them

Delete a key from your Dockerfile and the old image still has it. Docker layers are immutable — a credential baked in at build time lives in your registry forever unless you know how to hunt it down.

Your source code scans clean. Your Docker images don't. Images are a blind spot for most secrets programs because the leak usually isn't in a repository at all — it's created at build time and shipped to a registry, where it sits quietly for years. This guide covers the three ways secrets get into images, how to find them, and how to keep them out.

How secrets end up in images

1. Build arguments

The classic:

docker build --build-arg STRIPE_KEY=sk_live_... .

Build args are baked into the image's layer metadata. Even if the Dockerfile only uses the arg for a single RUN step, the value persists in the build history — readable by anyone with the image.

2. COPY of env and config files

COPY .env /app/.env

A .env in the build context is one careless line from being a permanent resident of the image. Same story for config files, key files, and anything else the app happens to need at build time.

3. RUN steps that pull credentials in

Cloning a private repo inside the build, downloading an artifact from an authenticated endpoint, installing a package with an embedded token — every one of these leaves credentials in intermediate layers, even when the final layer looks clean. Intermediate layers ship too.

Why "just delete it" doesn't work

Layers are immutable and content-addressed. Editing the Dockerfile and rebuilding creates a new image; the old layers — with the secret — remain in the registry, in caches, and on every machine that pulled them. Like git history, the only real fix is revocation plus rebuilding without the secret, never editing an existing image.

How to scan images for secrets

Scan every layer, not just the final filesystem. Secrets frequently live only in intermediate layers that never appear in the running container:

$ docker save your-image:tag -o image.tar
$ vooda scan image.tar --layers
⚠ [HIGH] Stripe Live Key — layer 3 (build-arg metadata)
⚠ [CRITICAL] AWS_SECRET_KEY — layer 7 (.env copied at build)

Vooda's image scanning unpacks each layer and runs the full 900+ rule engine against it, including build-arg metadata — the place most scanners miss. Pair it with a registry-wide scan so old tags and stale builds don't escape the net.

Keeping secrets out for good

Frequently asked questions

How do secrets end up in Docker images?

Three common paths: build arguments baked into layer metadata, COPY commands pulling in .env or config files, and RUN steps that clone private repos or download authenticated artifacts.

Can I delete a secret from a Docker image?

No — layers are immutable. Deleting the line from the Dockerfile creates a new image; the old layers with the secret remain in your registry and every pulled copy. Revoke and rebuild, never edit in place.

How do I scan a Docker image for secrets?

Scan every layer, not just the final filesystem — secrets often live only in intermediate layers. Vooda unpacks each layer and runs the full rule engine, including build-arg metadata most scanners miss.

How do I keep secrets out of Docker images?

Use BuildKit secrets instead of build args, never COPY .env files, use multi-stage builds, add .dockerignore entries, and scan images in CI before pushing to any registry.

What should I do if a Docker image contains a leaked secret?

Revoke the credential at its provider first, rebuild the image without it, delete or expire the compromised image and its tags from every registry, and audit what the secret could access.

Scan every layer, not just the code

Vooda scans Docker images layer by layer — plus repos, history, and 23+ non-code sources — so no baked-in credential escapes.