| name | docker-image-audit |
| description | Audit Docker images and Dockerfiles for security vulnerabilities, bloat, and best-practice violations using hadolint, Trivy, and Grype. Produces a structured severity report with actionable fixes. Use this skill whenever the user wants to check a Docker image for security issues, scan a container for vulnerabilities, audit a Dockerfile, harden a Docker image, reduce image size, minimize attack surface, check for CVEs in a container, or says things like "is this Dockerfile secure?", "scan my image", "check my container for vulnerabilities", "how can I make this image smaller?", "audit my Docker setup", or "harden this container". Also trigger when the user has just created or modified a Dockerfile and wants validation before shipping it. |
| role | worker |
| user-invocable | true |
Docker Image Audit
Audit Dockerfiles and container images using three complementary tools — hadolint (static Dockerfile linting), Trivy (CVE scanning), and Grype (second-opinion CVE scanning) — plus manual structural analysis for architectural issues the tools miss. Synthesize all findings into a single severity-ranked report with concrete fixes.
Prerequisites
command -v hadolint && command -v trivy && command -v grype
| Tool | Quick install (macOS) | Purpose |
|---|
| hadolint | brew install hadolint | Static Dockerfile analysis |
| trivy | brew install trivy | Vulnerability scanning |
| grype | brew install grype | Second-opinion CVE scanning |
If any tool is missing, run /project-init to set up this repo's tooling — it installs hadolint/trivy/grype as capability tools when a Dockerfile is present (see its ${CLAUDE_PLUGIN_ROOT}/skills/project-init/references/capability-tools.md) — or install these Docker tools directly per references/install-guide.md (multi-platform; the install-guide is the fallback). The skill degrades gracefully — hadolint alone covers static analysis; Trivy + Grype require a built image. If no tools are installed, still run the structural analysis (Step 2b). A tool-free audit is better than no audit.
Workflow
Step 1: Identify the Target
- Dockerfile only — hadolint + structural analysis (no built image needed)
- Built image — Trivy + Grype (image must exist locally or in a registry)
- Both — all steps (default when both are available)
If the user points to a Dockerfile but no built image exists, offer to build it or proceed with Dockerfile-only analysis.
Step 2: Hadolint
hadolint --format json Dockerfile
Catches base image issues (:latest tag, unpinned versions), security anti-patterns (ADD vs COPY, running as root), efficiency problems (missing --no-cache, uncleaned apt cache), and shell issues in RUN instructions via integrated ShellCheck. Note: hadolint flags :latest (DL3007) but not other unpinned tags like :10.0 without a digest — call those out in Step 2b (Structural Analysis) if the base image lacks a specific patch version or SHA digest.
Step 2b: Structural Analysis
Hadolint catches per-instruction issues but misses architectural problems. Read the Dockerfile and check for these patterns — they are not optional and often represent the most impactful findings.
| Check | What to look for | Severity |
|---|
| "God Dockerfile" | CI/CD baked into the build: SonarQube, Black Duck, Snyk, Helm packaging, curl uploads to Nexus/Artifactory, npm publish, git clone. The Dockerfile should produce a runnable image — everything else belongs in CI pipeline definitions. | HIGH |
| Secrets in ARGs | ARG names matching *_TOKEN, *_SECRET, *_KEY, *_PASSWORD, *_CREDENTIALS. ARGs persist in image layer metadata (docker history --no-trunc). Fix: use RUN --mount=type=secret. If secrets are only for CI stages, the better fix is moving those stages out of the Dockerfile. | HIGH |
| Missing .dockerignore + broad COPY | COPY . . without a .dockerignore sends .git/, node_modules/, bin/, obj/, IDE config, and local secrets into the build context. | HIGH |
| Config mismatch | Building/testing in Debug but publishing in Release (or vice versa). Tests should validate the exact bits that ship. Also flag post-build jq/sed/awk patching of output files — suggests misconfigured build flags. | MEDIUM |
| Redundant COPY | Broad COPY . . followed by selective copies (redundant); same files re-copied across stages; COPY . . before RUN <restore> busting the dependency cache. Fix: copy manifests first (*.csproj, package-lock.json, go.sum), restore, then copy source. | MEDIUM |
| TLS verification disabled | --insecure-skip-tls-verify, curl -k, NODE_TLS_REJECT_UNAUTHORIZED=0, GIT_SSL_NO_VERIFY=true. Vulnerable to MITM. Fix: configure proper CA certs. |
Step 3: Trivy
Run if a built image or project filesystem is available:
trivy image --format json --severity CRITICAL,HIGH,MEDIUM,LOW --output trivy-report.json <image>
trivy fs --format json --severity CRITICAL,HIGH,MEDIUM,LOW --output trivy-fs-report.json .
The image scan catches OS package CVEs; the filesystem scan catches application dependency CVEs (npm, pip, Go, Maven, etc.). Also supports --scanners misconfig,secret for bonus coverage.
Step 4: Grype
grype <image> -o json > grype-report.json
Cross-validates against Anchore's vulnerability database. When both Trivy and Grype flag a CVE, confidence is high. When only one flags it, note the disagreement — the user should investigate.
Step 5: Image Size & Layers
docker image inspect <image> --format '{{.Size}}'
docker history <image> --no-trunc --format '{{.Size}}\t{{.CreatedBy}}'
Flag layers over 100MB, build artifacts in the final image (compilers, dev headers), package manager caches, and opportunities to switch to distroless/slim bases.
Step 6: Write the Report
Write findings to docker-audit-report.md in the project root (not chat). Use the template in references/report-template.md for structure. Every finding needs a source, severity, description, and concrete fix.
Severity Classification
| Severity | Criteria |
|---|
| CRITICAL | Actively exploited CVE, RCE, exposed secrets in final image |
| HIGH | Known CVE with public exploit, secrets in ARGs, "God Dockerfile", missing .dockerignore + broad COPY, root in final stage |
| MEDIUM | Known CVE without public exploit, missing HEALTHCHECK, unpinned base, config mismatch, redundant COPY, TLS disabled, baked-in configuration, Swiss Army Knife image, stateful container patterns, language-specific anti-patterns |
| LOW | Informational CVE, dead-end stages, UID/GID mismatch, root in build-only stages |
| INFO | Style suggestions, layer consolidation opportunities |
Quick Audit Mode
For fast passes (e.g., "quick check on this Dockerfile"), run Step 2 (hadolint) + Step 2b (structural analysis) and report findings conversationally — no report file. Skip Steps 3-5. Mention that a full image scan with Trivy + Grype is available for deeper CVE analysis.