Dockerfile Review Skill
Summary
- The Dockerfile Review Skill is a packaged automation that reviews a Dockerfile against a fixed security and build-cache checklist and returns prioritized findings with corrected snippets.
- Insight: Most Dockerfile defects fall into two buckets - security posture (root, unpinned bases, leaked secrets) and cache efficiency (instruction order) - so a small, well-ordered checklist catches the overwhelming majority.
- Key Concepts: multi-stage builds, layer caching, base image pinning, non-root
USER, build secrets, and.dockerignore. - When to Use: Run it on every Dockerfile change in CI, before the image is built and long before it reaches a cluster.
- Limitations: It reviews the Dockerfile text and the resulting image metadata; it does not audit application code or runtime behavior, and it needs a scanner like Trivy for CVE coverage.
Recipe
The shortest path is a static lint plus a scan of the built image.
hadolint Dockerfile
docker buildx build -t myapp:$SHA .
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:$SHAhadolint enforces Dockerfile best practices; Trivy catches vulnerable packages in the final image.
The skill wraps these, adds its own criteria, and returns each finding with a rationale and a fix.
Working Example
Here is a Dockerfile with the defects the skill flags, followed by the corrected version.
Before:
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
ENV API_TOKEN=sk-live-abc123
EXPOSE 3000
CMD ["node", "server.js"]The skill flags five issues: a mutable base tag, copying the full context before installing dependencies, npm install instead of npm ci, a hardcoded secret in an ENV, and no non-root USER.
After:
# Stage 1: install dependencies with a cacheable layer
FROM node:22.11-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# Stage 2: minimal runtime image
FROM node:22.11-bookworm-slim
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]The base is pinned to a patch tag and slim variant.
Dependencies install in their own stage from package.json and the lockfile, so a source-only change reuses the cached layer.
The secret is gone; it belongs in a Kubernetes Secret mounted at runtime, not baked into a layer.
The final stage runs as the built-in unprivileged node user.
Deep Dive
Cache order is about instruction stability
Docker caches each layer by the instruction and its inputs; a layer rebuilds only if it or an earlier layer changed.
Put the least-frequently-changing steps first - copy the lockfile and install dependencies before copying source that changes on every commit.
Getting this wrong turns a two-second rebuild into a full reinstall on every push.
Multi-stage builds shrink the attack surface
Build tooling, compilers, and dev dependencies do not belong in the shipped image.
A deps or build stage produces artifacts; the final stage copies only what runtime needs.
Smaller images pull faster and expose fewer packages to CVEs.
Base image pinning trades convenience for reproducibility
A floating tag like node:22 can change under you between builds, breaking reproducibility and slipping in new vulnerabilities.
Pin to a patch tag such as node:22.11-bookworm-slim, or to a digest (node@sha256:...) when you need byte-for-byte reproducibility.
The skill flags any FROM without a specific tag or digest.
Build secrets never belong in layers
An ENV or ARG secret is readable in the image history via docker history.
Use BuildKit's --secret mount, which exposes the value only during a single RUN and never writes it to a layer.
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ciA .dockerignore keeps the context clean
Without one, COPY . . drags in .git, node_modules, and local .env files - bloating the image and risking secret leakage.
The skill checks that a .dockerignore exists and excludes those paths.
Gotchas
Copying source before installing dependencies is the most common cache mistake and silently wastes CI minutes on every build.
Using npm install instead of npm ci ignores the lockfile and can pull different versions than tested; the skill flags it.
Setting USER before a RUN that needs to write to a root-owned path fails the build; place USER after privileged setup steps.
A pinned base still goes stale - pair the pin with a scheduled Trivy scan so you learn when the pinned version gains a CVE.
EXPOSE documents a port but does not publish it; do not rely on it for network policy.
Alternatives
hadolint alone is a fast, zero-config Dockerfile linter and is the right baseline when you only need static rules.
Buildpacks (Paketo, pack) skip the Dockerfile entirely and generate optimized, non-root images from source, which suits teams that want to avoid maintaining Dockerfiles at all.
docker scout provides image analysis and base-image recommendations integrated with Docker Engine, overlapping with Trivy on CVE detection.
Choose the review skill when you want consistent, explained findings across many teams; choose buildpacks when you want to remove Dockerfile authorship from the picture.
FAQs
Should the skill block the build or just warn?
Block on hard security failures like leaked secrets or root users; warn on style and cache issues so teams can triage without a broken pipeline.
Does it detect secrets already committed to layers?
Yes for common patterns in ENV/ARG and via image history scanning, but treat any leaked secret as compromised and rotate it regardless.
How does it handle language-specific images?
The checklist is language-agnostic for security and cache order; the reference fixes adapt the install command (npm ci, pip install --no-cache-dir, go build) per ecosystem.
Can it enforce digest pinning?
Yes - it can require FROM to use a digest, though many teams accept patch tags as a pragmatic middle ground.
Does it replace Trivy?
No - it orchestrates Trivy for CVE findings and adds Dockerfile-structure criteria that a scanner does not check.
Related
- What a Packaged SME Skill Is
- Agent Skills Basics
- Kubernetes Manifest Skill
- Incident Triage Skill
- Agent Skills Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).