Dockerfile Security Review with AI: Catching Footguns Before Build
Most container risk is baked in at build time. Here's how I use AI to review Dockerfiles for root users, leaked secrets, fat images, and unpinned bases before they ever ship.
- #security
- #hardening
- #docker
- #containers
- #ai
By the time a container is scanned at runtime, most of its security posture is already fixed. It was decided in the Dockerfile: whether it runs as root, whether a build secret got baked into a layer, whether the base image is a known-good pinned digest or a moving latest tag, whether the final image carries a compiler and a package manager that an attacker can turn against you.
I review Dockerfiles the way I review any other security-critical config, because the cost of catching a problem here — before build — is trivial compared to catching it in production. The patterns are well-known, which makes this an ideal first-pass job for AI: a defensive review that flags the footguns so I can fix them. Here’s how I do it without handing the model anything it shouldn’t have.
What gets baked in wrong
The recurring Dockerfile security problems:
- Running as root — no
USERdirective, so the process runs as root inside the container, widening the blast radius of any escape. - Secrets in layers —
ARG/ENVor a copied.envfile embedding a token that survives in the image history forever, even if “removed” in a later layer. - Unpinned base images —
FROM node:latestinstead of a pinned digest, so your build is non-reproducible and silently follows upstream changes. - Fat images — full OS bases carrying shells, package managers, and build tools the running app never needs but an attacker would love.
- Curl-pipe-bash installs —
RUN curl ... | bashpulling and executing unverified remote code at build time.
Every one of these is visible in the Dockerfile. None requires running the image. That’s what makes the review cheap.
Feed the Dockerfile and the build context inventory
The Dockerfile alone isn’t the whole story — what gets copied in matters too. So I also list the context and the .dockerignore:
# The Dockerfile itself
cat Dockerfile
# What would actually be copied into the image
cat .dockerignore 2>/dev/null
git ls-files | grep -iE '\.env|\.pem|\.key|credentials|secret' || echo "none tracked"
That last grep is a quick check for sensitive files sitting in the build context that a broad COPY . . would sweep into the image. If it returns anything, that’s the first thing to fix — and a missing or thin .dockerignore is often the root cause.
A Dockerfile security review prompt
I scope the model to build-time security and ask for ranked, explained findings:
You are a container security reviewer auditing a Dockerfile. Find
security issues ONLY, ranked by severity:
1. Privilege: does the image run as root? Is there a non-root USER?
2. Secrets: any ARG/ENV holding a credential, or a COPY that could pull
secrets/.env/keys into a layer (note: layer history persists them).
3. Base image: is FROM pinned to a digest or a specific version, or a
moving tag like latest?
4. Attack surface: is this a minimal/distroless/slim base, or a full OS
carrying unneeded shells, package managers, and build tools?
5. Remote code: any curl|bash or unverified download executed at build.
6. Multi-stage: are build tools leaking into the final runtime image?
Explain each finding's impact. Do not rewrite the Dockerfile.
<paste Dockerfile + .dockerignore>
The secret-in-layer finding is the one people most underestimate. A Dockerfile that does this:
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc \
&& npm ci \
&& rm .npmrc
looks safe because it deletes the .npmrc — but the token is still in the layer where it was written, recoverable by anyone with the image. The model catches this and points you at the right fix: BuildKit secret mounts, which never persist the secret in any layer:
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npmtoken \
NPM_TOKEN=$(cat /run/secrets/npmtoken) npm ci
Pro Tip: Ask the model to reason about Docker’s layer model explicitly: “Which secrets, if any, would survive in the image history even though a later RUN deletes them?” The persistence-across-layers reasoning is the single most valuable thing an AI review catches here, because it’s the mistake that looks fixed but isn’t.
Harden toward minimal and non-root
The fixes follow a familiar shape — pin the base, drop privileges, go minimal, and use multi-stage builds so compilers never reach production:
# Pinned base, multi-stage so build tools don't ship
FROM golang:1.22@sha256:abc... AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server
# Minimal distroless runtime, non-root by default
FROM gcr.io/distroless/static:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
The AI proposes these patterns well, but a generated multi-stage Dockerfile needs to actually build and run your app — I verify it locally before it goes anywhere near a pipeline. The review pairs with runtime scanning; a clean build review plus Trivy image scanning and AI triage covers both ends of the lifecycle, and hardening the Docker daemon covers the host.
Review every Dockerfile change
Dockerfiles change as dependencies and bases evolve, and each change can reintroduce an old footgun. I run this review on every Dockerfile diff, the way our code review dashboard flags risky changes in general. I drive the review with Claude or directly in Cursor against the file, and keep the prompts reusable in the prompt library.
Defensive, verified, secrets-free
The model is a fast junior container reviewer — it knows the layer-persistence trap, the non-root pattern, and the minimal-base playbook cold, and it never skims past them. But it can suggest a base image that doesn’t fit your runtime, or a multi-stage layout that doesn’t quite build, so I always verify the generated Dockerfile actually builds and runs before adopting it. And I never paste real registry tokens, build secrets, or .env contents into the prompt — the structure of the Dockerfile is what the model reviews, never the secret values themselves.
Conclusion
Container security is mostly decided at build time, which means the cheapest place to fix it is the Dockerfile. An AI reviewer makes a thorough build-time audit fast and repeatable — privilege, secrets-in-layers, base pinning, attack surface — while you stay the human who confirms the image still builds and keeps real secrets out of the prompt. Make it a standing part of your security and hardening workflow.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.