Files
gh-agentsecops-secopsagentkit/skills/devsecops/container-hadolint/references/security_rules.md
2025-11-29 17:51:02 +08:00

9.2 KiB

Hadolint Security Rules Reference

Complete reference of Hadolint security rules with CIS Docker Benchmark mappings and remediation guidance.

Table of Contents

Critical Security Rules

DL3000: Use absolute WORKDIR

Severity: Error CIS Mapping: 4.10 - Ensure secrets are not stored in Dockerfiles

Issue: Relative WORKDIR can lead to path confusion and security vulnerabilities.

Bad:

WORKDIR app

Good:

WORKDIR /app

DL3001: Version pinning for package managers

Severity: Warning CIS Mapping: 4.3 - Do not install unnecessary packages

Issue: Unpinned versions lead to non-reproducible builds and potential security vulnerabilities from package updates.

Bad:

RUN yum install httpd

Good:

RUN yum install -y httpd-2.4.51

DL3002: Never switch back to root

Severity: Error CIS Mapping: 4.1 - Create a user for the container

Issue: Switching back to root defeats container isolation and violates least privilege principle.

Bad:

USER node
RUN npm install
USER root  # ❌ Don't switch back to root

Good:

USER node
RUN npm install
# Stay as non-root user

DL3003: Use WORKDIR instead of cd

Severity: Warning CIS Mapping: Best practices

Issue: Using cd in RUN commands doesn't persist across instructions and can cause confusion.

Bad:

RUN cd /app && npm install

Good:

WORKDIR /app
RUN npm install

DL3006: Always tag image versions

Severity: Warning CIS Mapping: 4.3 - Ensure base images are verified

Issue: Using :latest or no tag creates non-reproducible builds and security risks.

Bad:

FROM node
FROM ubuntu:latest

Good:

FROM node:18.19.0-alpine3.19
FROM ubuntu:22.04

DL3007: Pin Docker image versions to specific digest

Severity: Info CIS Mapping: 4.3 - Ensure base images are verified

Issue: Tags can be overwritten; digests are immutable.

Good:

FROM node:18.19.0-alpine3.19

Better:

FROM node:18.19.0-alpine3.19@sha256:abc123...

DL3008: Pin apt-get package versions

Severity: Warning CIS Mapping: 4.3 - Do not install unnecessary packages

Issue: Unpinned apt packages lead to non-reproducible builds.

Bad:

RUN apt-get update && apt-get install -y curl

Good:

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    curl=7.68.0-1ubuntu2.14 && \
    rm -rf /var/lib/apt/lists/*

DL3009: Delete apt cache after installation

Severity: Info CIS Mapping: 4.6 - Reduce image size

Issue: Unnecessary cache increases image size and attack surface.

Bad:

RUN apt-get update && apt-get install -y curl

Good:

RUN apt-get update && \
    apt-get install -y curl && \
    rm -rf /var/lib/apt/lists/*

DL3013: Pin pip package versions

Severity: Warning CIS Mapping: 4.3 - Do not install unnecessary packages

Issue: Unpinned pip packages compromise build reproducibility.

Bad:

RUN pip install flask

Good:

RUN pip install --no-cache-dir flask==2.3.2

DL3020: Use COPY instead of ADD

Severity: Error CIS Mapping: 4.9 - Use COPY instead of ADD

Issue: ADD has implicit behavior (auto-extraction, URL support) that can be exploited.

Bad:

ADD app.tar.gz /app/
ADD https://example.com/file.txt /tmp/

Good:

COPY app.tar.gz /app/
# For URLs, use RUN wget/curl instead
RUN curl -O https://example.com/file.txt

Exception: ADD is acceptable only when you explicitly need tar auto-extraction.


DL3025: Use JSON notation for CMD and ENTRYPOINT

Severity: Warning CIS Mapping: 4.6 - Add HEALTHCHECK instruction

Issue: Shell form enables shell injection attacks and doesn't properly handle signals.

Bad:

CMD node server.js
ENTRYPOINT /app/start.sh

Good:

CMD ["node", "server.js"]
ENTRYPOINT ["/app/start.sh"]

DL3028: Use credentials via build secrets

Severity: Warning CIS Mapping: 4.10 - Do not store secrets in Dockerfiles

Issue: Credentials in ENV or ARG end up in image layers.

Bad:

ARG API_KEY=secret123
RUN curl -H "Authorization: $API_KEY" https://api.example.com

Good (BuildKit secrets):

# syntax=docker/dockerfile:1.4
RUN --mount=type=secret,id=api_key \
    curl -H "Authorization: $(cat /run/secrets/api_key)" https://api.example.com

DL3059: Multiple RUN instructions

Severity: Info CIS Mapping: 4.6 - Optimize layers

Issue: Multiple RUN instructions create unnecessary layers, increasing image size.

Less Optimal:

RUN apt-get update
RUN apt-get install -y curl
RUN curl -O https://example.com/file

Better:

RUN apt-get update && \
    apt-get install -y curl && \
    curl -O https://example.com/file && \
    rm -rf /var/lib/apt/lists/*

Note: Balance between layer caching and image size. For development, separate RUN instructions may aid caching.


CIS Docker Benchmark Mappings

CIS 4.1: Create a user for the container

Hadolint Rules: DL3002

Requirement: Don't run containers as root.

Implementation:

RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
# Don't switch back to root

CIS 4.3: Do not install unnecessary packages

Hadolint Rules: DL3001, DL3008, DL3013, DL3015

Requirement: Minimize attack surface by installing only required packages with pinned versions.

Implementation:

# Use --no-install-recommends
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    package1=version1 \
    package2=version2 && \
    rm -rf /var/lib/apt/lists/*

CIS 4.6: Add HEALTHCHECK instruction

Hadolint Rules: DL3025 (related to proper CMD/ENTRYPOINT)

Requirement: Include HEALTHCHECK to enable container health monitoring.

Implementation:

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

CIS 4.7: Do not use update instructions alone

Hadolint Rules: DL3009, DL3014, DL3015

Requirement: Update and install should be in same RUN instruction to prevent cache issues.

Implementation:

# Bad
RUN apt-get update
RUN apt-get install -y package

# Good
RUN apt-get update && \
    apt-get install -y package && \
    rm -rf /var/lib/apt/lists/*

CIS 4.9: Use COPY instead of ADD

Hadolint Rules: DL3020

Requirement: Use COPY for file operations; ADD only for tar extraction.

Implementation: See DL3020 above.


CIS 4.10: Do not store secrets in Dockerfiles

Hadolint Rules: DL3028, DL3000 (indirectly)

Requirement: Use build secrets or external secret management.

Implementation: See DL3028 above.


Rule Categories

Base Image Security

  • DL3006: Always tag image versions
  • DL3007: Use specific image digests
  • DL3026: Use trusted registries only

Package Management

  • DL3001: Version pinning (yum/dnf/zypper)
  • DL3008: Version pinning (apt-get)
  • DL3013: Version pinning (pip)
  • DL3016: Version pinning (npm)
  • DL3018: Version pinning (apk)
  • DL3028: Use build secrets for credentials

Instruction Best Practices

  • DL3000: Use absolute WORKDIR
  • DL3003: Use WORKDIR instead of cd
  • DL3020: Use COPY instead of ADD
  • DL3025: Use JSON notation for CMD/ENTRYPOINT

User and Permissions

  • DL3002: Never switch back to root
  • DL4001: Use SHELL to switch shells securely

Image Optimization

  • DL3009: Delete apt cache
  • DL3014: Use -y for apt-get
  • DL3015: Avoid additional packages
  • DL3059: Minimize RUN instructions

ShellCheck Integration

  • DL4000-DL4006: Shell script best practices in RUN

Quick Reference Table

Rule Severity CIS Description
DL3000 Error 4.10 Use absolute WORKDIR
DL3001 Warning 4.3 Pin yum versions
DL3002 Error 4.1 Don't switch to root
DL3003 Warning - Use WORKDIR not cd
DL3006 Warning 4.3 Tag image versions
DL3007 Info 4.3 Use image digests
DL3008 Warning 4.3 Pin apt versions
DL3009 Info 4.7 Delete apt cache
DL3013 Warning 4.3 Pin pip versions
DL3020 Error 4.9 Use COPY not ADD
DL3025 Warning 4.6 JSON notation CMD
DL3028 Warning 4.10 Use build secrets
DL3059 Info - Multiple RUN instructions

Additional Resources