Dockerfile Rules (D01-D40)
40 rules for Dockerfile security and best practices. Deducts from the Security Score.
Base Image Security (D01-D05)
| ID | Sev | Pts | Description | Fix |
| D01 | CRIT | 3 | Using FROM with :latest tag | Pin to specific version: FROM ubuntu:22.04 |
| D02 | HIGH | 3 | FROM without any tag or digest | Add explicit version tag: FROM node:20-alpine |
| D03 | HIGH | 3 | No non-root USER instruction | Add USER 1001 before CMD instruction |
| D04 | MED | 2 | Using ADD instead of COPY | Replace ADD with COPY unless archive extraction needed |
| D05 | HIGH | 3 | Using large base image instead of slim/alpine | Use alpine, slim, or distroless variant |
Secrets & Sensitive Data (D06-D10)
| ID | Sev | Pts | Description | Fix |
| D06 | CRIT | 5 | Secret in ENV or ARG instruction | Use --secret mount or runtime env vars instead |
| D07 | HIGH | 3 | COPY of sensitive files into image | Use Docker secrets or mount at runtime |
| D08 | MED | 2 | Git clone with embedded credentials | Use SSH agent forwarding or build-time --secret mount |
| D09 | MED | 2 | ssh-keygen or SSH key generation in Dockerfile | Generate SSH keys at runtime or mount from secret manager |
| D10 | HIGH | 3 | Curl piped to shell (pipe install pattern) | Download, verify checksum, then execute separately |
Build Instructions (D11-D15)
| ID | Sev | Pts | Description | Fix |
| D11 | MED | 2 | CMD in shell form instead of exec form | Use exec form: CMD ["npm", "start"] |
| D12 | MED | 2 | ENTRYPOINT in shell form | Use exec form: ENTRYPOINT ["./app"] |
| D13 | MED | 2 | No HEALTHCHECK instruction | Add HEALTHCHECK CMD curl -f http://localhost/ || exit 1 |
| D14 | LOW | 1 | No WORKDIR instruction | Add WORKDIR /app before COPY and RUN |
| D15 | LOW | 1 | No EXPOSE instruction | Add EXPOSE 8080 to document container port |
Package Management (D16-D20)
| ID | Sev | Pts | Description | Fix |
| D16 | HIGH | 3 | apt-get install without --no-install-recommends | Add --no-install-recommends to apt-get install |
| D17 | MED | 2 | apt-get upgrade or dist-upgrade in Dockerfile | Remove apt-get upgrade - pin specific versions |
| D18 | MED | 2 | apk add without --no-cache | Add --no-cache: RUN apk add --no-cache curl |
| D19 | MED | 2 | pip install without --no-cache-dir | Add --no-cache-dir to pip install |
| D20 | MED | 2 | pip install without version pinning | Pin versions or use requirements.txt |
Multi-Stage & Layer Optimization (D21-D25)
| ID | Sev | Pts | Description | Fix |
| D21 | HIGH | 3 | No multi-stage build | Use multi-stage: FROM node AS build ... FROM alpine |
| D22 | MED | 2 | COPY . . without .dockerignore | Create .dockerignore with .git, node_modules, .env |
| D23 | MED | 2 | Multiple consecutive RUN instructions | Combine RUN commands with && on single layer |
| D24 | MED | 2 | Package install without cleanup in same layer | Add && rm -rf /var/lib/apt/lists/* in same RUN |
| D25 | MED | 2 | COPY before package.json (bad cache order) | COPY package*.json first, then COPY . . |
Security Hardening (D26-D30)
| ID | Sev | Pts | Description | Fix |
| D26 | HIGH | 3 | SETUID/SETGID binaries not removed | RUN find / -perm /6000 -exec chmod a-s {} + |
| D27 | CRIT | 3 | chmod 777 - world-writable permissions | Use chmod 755 for dirs, chmod 644 for files |
| D28 | HIGH | 3 | Using sudo in Dockerfile | Remove sudo - run as root before USER, then switch |
| D29 | MED | 2 | No checksum verification for downloaded files | Verify: curl -o file URL && sha256sum -c checksum.txt |
| D30 | MED | 2 | No init process (PID 1 signal handling) | Install tini: ENTRYPOINT ["tini", "--"] |
Best Practices (D31-D35)
| ID | Sev | Pts | Description | Fix |
| D31 | LOW | 1 | No LABEL instruction for metadata | Add LABEL maintainer="you" version="1.0" |
| D32 | MED | 2 | Multiple CMD instructions | Keep only one CMD at the end of Dockerfile |
| D33 | MED | 2 | Multiple ENTRYPOINT instructions | Keep only one ENTRYPOINT instruction |
| D34 | LOW | 1 | No .dockerignore file referenced | Create .dockerignore with .git, node_modules, .env |
| D35 | LOW | 1 | No Hadolint or Dockerfile linting configured | Add .hadolint.yaml and run hadolint in CI |
Advanced (D36-D40)
| ID | Sev | Pts | Description | Fix |
| D36 | MED | 2 | Using VOLUME for application data | Define volumes in docker-compose or K8s, not Dockerfile |
| D37 | HIGH | 3 | Running as root at end of Dockerfile | Add USER 1001 after root operations, before CMD |
| D38 | MED | 2 | SHELL override without justification | Only override SHELL for PowerShell or specific features |
| D39 | MED | 2 | ADD with URL source | Replace ADD URL with RUN curl + sha256sum verification |
| D40 | HIGH | 3 | Using --privileged or dangerous capabilities | Drop all capabilities and add only what is needed |
Total: 40 rules across 8 sections. All deduct from the Security Score.