Dockerfile Linter — Security & best-practices checker avatar

Dockerfile Linter — Security & best-practices checker

Pricing

from $0.02 / dockerfile lint

Go to Apify Store
Dockerfile Linter — Security & best-practices checker

Dockerfile Linter — Security & best-practices checker

Lint Dockerfiles and docker-compose files against 15+ security and best-practice rules. Detects running as root, missing USER directive, unpinned packages, missing HEALTHCHECK, and more. Supports strict mode and batch linting.

Pricing

from $0.02 / dockerfile lint

Rating

0.0

(0)

Developer

Perry AY

Perry AY

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 hours ago

Last modified

Categories

Share

🐳 Dockerfile Linter — Security & Best-Practices Checker

Automated Dockerfile and docker-compose linter that enforces 21 security and quality rules out of the box — from containers running as root to missing HEALTHCHECK directives, unpinned package versions, and insecure COPY patterns. Integrates into any CI/CD pipeline with a strict mode that can gate deployments on ERROR-level findings.

Modern container workflows move fast, but fast shouldn't mean fragile. Every Dockerfile and docker-compose configuration that ships to production carries implicit security and operational decisions — which base image to use, whether the container runs as root, how dependencies are installed, and whether the orchestrator can health-check the service. The Dockerfile Linter automates the review of these decisions across 21 rules (14 for Dockerfiles, 7 for docker-compose), producing structured findings with severity levels, remediation suggestions, and a quantitative pass score. No more relying on manual code reviews to catch container misconfigurations.

Designed for DevSecOps teams, platform engineers, and CI/CD pipelines, the linter accepts Dockerfile content directly, reads from a file path, or fetches from a URL or Apify Key-Value Store. It produces machine-readable JSON output suitable for downstream processing — dashboarding, alerting, or automated rollback gates. With strict mode enabled, any ERROR-level finding causes the run to fail, making it a drop-in quality gate for GitHub Actions, GitLab CI, Jenkins, or any CI/CD system that supports actor/webhook integration.


What does it do?

The Dockerfile Linter analyses container build instructions against a comprehensive rule set derived from Docker best practices, CIS Docker Benchmark recommendations, and real-world production incidents. It operates in three modes — Dockerfile-only, docker-compose-only, or both — and returns a structured lint report for each.

For Dockerfiles, the linter scans every line for 14 distinct rules (coded DL3000–DL3015, excluding retired rules DL3012 and DL3014) covering base image tagging, user context, instruction choice (ADD vs COPY), multi-stage build hygiene, package manager discipline, and production-readiness checks like HEALTHCHECK. Rules are classified as ERROR, WARNING, or INFO so teams can triage findings by impact. The linter handles multi-stage builds intelligently — for example, DL3003 only flags a missing USER directive in the final stage, not in intermediate builder stages where root access may be legitimate.

For docker-compose files, the linter parses YAML service definitions and validates 7 policy rules (coded DC1000–DC1006) covering versioning, restart policies, resource limits, privileged mode, image tag pinning, health check configuration, and volume type decisions. Each service is checked independently, so a multi-service compose file gets per-service findings.

Every lint run produces a Pass Score on a 0–100 scale. ERROR-level findings deduct 20 points each, WARNING-level findings deduct 5 points each, and INFO findings are advisory only. A score of 70 or above is considered passing. When strict mode is enabled, the presence of any ERROR finding causes the run to report as failed — ideal for CI/CD gates where zero-tolerance policies apply.


Who is it for?

PersonaWhy this actor matters
DevSecOps EngineerEnforce security baselines across every container image built in the organisation. Block PRs with root containers or unpinned base images before they merge.
Platform / SRE EngineerEnsure every service in the platform has HEALTHCHECK, resource limits, and restart policies defined. Catch privileged: true usage before it reaches production.
Software EngineerGet instant feedback on Dockerfile quality during development. Learn best practices through structured remediation suggestions without memorising rule numbers.
CI/CD Pipeline ArchitectDrop the actor into any pipeline (GitHub Actions, GitLab CI, Jenkins, Argo Workflows) as a quality gate. Use the JSON output for dashboards, Slack alerts, or automated rollback decisions.
Container Security AuditorBatch-audit Dockerfiles across microservices repositories in a single run. Generate compliance evidence for CIS Docker Benchmark adherence.
DevOps Onboarding LeadStandardise container configuration quality across teams. The linter serves as an automated code reviewer that never misses a best-practice check.

Why use this?

  • 21 rules, zero configuration — Rules cover the OWASP Docker security cheat sheet, CIS Docker Benchmark Level 1 & 2 controls, and community best practices. No config files to write, no plugin installs, no registry setup.
  • CI/CD-ready strict mode — Flip strictMode: true and the actor fails on any ERROR finding. Integrates with GitHub Actions, GitLab CI, Jenkins, CircleCI, and Argo Workflows in minutes.
  • Quantitative pass scoring — Every run produces a 0–100 score so you can trend quality over time, compare across teams, and set progressive quality targets (e.g., "all services must score ≥ 85").
  • Structured, machine-readable output — Findings include rule ID, severity, title, description, remediation advice, line number, and offending text. Use the JSON output to build custom dashboards, trigger alerts, or feed into Jira automation.
  • Multi-mode linting — Lint Dockerfiles, docker-compose files, or both in a single run. Supports content pasted directly, file paths, or URL/KVS lookups.
  • Intelligent multi-stage analysis — Rules that apply only to the final stage (root user check) are evaluated correctly, avoiding false positives on builder stages.
  • Remediation guidance built in — Every finding includes actionable remediation text. Engineers don't need to search Stack Overflow to fix a DL3004 or DC1002 issue.
  • No vendor lock-in — Runs on the Apify platform but the rule engine is pure Python with no proprietary dependencies. The actor's source is available and extensible.

Features

Dockerfile Rules — DL3000 to DL3015 (14 checks)

IDSeverityRuleWhat It ChecksWhy It Matters
DL3000🔴 ERRORPin base image tagsFROM python:latest detectedlatest changes silently — breaks reproducibility and can introduce breaking OS/package changes mid-release
DL3001🟠 WARNINGAdd USER directiveNo USER line found in the entire DockerfileRoot containers are a top-10 container security risk. If compromised, the attacker has full host-level access (depending on runtime)
DL3002🟠 WARNINGPrefer COPY over ADDADD instruction used for local filesADD has hidden behaviours (automatic tar extraction, remote URL fetching) that create opaque builds and potential security surprises
DL3003🔴 ERRORNo root user in final stageFinal build stage lacks a USER directiveEven if earlier stages have users, the final running image defaults to root unless explicitly switched. A common oversight in multi-stage builds
DL3004🟠 WARNINGPin apt package versionsapt-get install curl (no =version)Unpinned packages produce different results on different build dates. Pin versions for deterministic, auditable builds
DL3005🟠 WARNINGCombine apt-get update && installSeparate RUN apt-get update and RUN apt-get installSeparate instructions create an extra layer and risk caching a stale apt-get update while picking up newer packages — a security gap
DL3006ℹ️ INFORemove apt lists after installMissing rm -rf /var/lib/apt/lists/*Leftover apt lists add significant bloat (50–100 MB per layer). Clean up in the same RUN instruction
DL3007🟠 WARNINGAvoid sudo in RUNRUN sudo ... pattern detectedsudo inside a Dockerfile indicates the container is running as root or has inconsistent user switching. Either way, the permission model needs review
DL3008🟠 WARNINGUse WORKDIR not RUN cdRUN cd /app && ... patternRUN cd only affects that single shell command. WORKDIR sets the working directory for all subsequent instructions and is self-documenting
DL3009🔴 ERRORAdd HEALTHCHECK instructionNo HEALTHCHECK found in the DockerfileOrchestrators (Kubernetes, Docker Swarm, ECS) rely on HEALTHCHECK for traffic routing and self-healing. Missing it means downtime isn't detected automatically
DL3010ℹ️ INFOUse COPY --chownCOPY without --chown flagSetting ownership at copy time eliminates the need for a separate RUN chown layer, reducing image size and build time
DL3011🟠 WARNINGName multi-stage build stagesFROM ... AS missing in multi-stage buildsUnnamed stages make the Dockerfile harder to read and prevent --target selective builds
DL3013🟠 WARNINGUse pip --no-cache-dirpip install without --no-cache-dirPip cache adds 10–100 MB per layer. Add --no-cache-dir to keep images lean
DL3015🟠 WARNINGUse --no-install-recommendsapt-get install without --no-install-recommendsRecommends packages add substantial image bloat — often doubling the layer size for utility packages

Docker-Compose Rules — DC1000 to DC1006 (7 checks)

IDSeverityRuleWhat It ChecksWhy It Matters
DC1000ℹ️ INFOAdd version fieldCompose file missing versionWhile recent Docker Compose v2 treats version as optional, specifying it ensures compatibility across different Docker Engine versions and CI runners
DC1001🟠 WARNINGDefine restart policyService missing restart configurationWithout a restart policy, a crashed or OOM-killed service stays down until manually restarted. Production services should use unless-stopped or always
DC1002🟠 WARNINGSet resource limitsService missing deploy.resources.limitsUnbounded services can consume all host memory or CPU, starving sibling containers and triggering OOM kills across the node
DC1003🔴 ERRORAvoid privileged modeService has privileged: truePrivileged mode grants full host capabilities — device access, kernel namespace manipulation, and bypass of seccomp/AppArmor. Equivalent to running the container as root on the host
DC1004🟠 WARNINGPin image tagsService uses image: myapp or :latestUnpinned images break rolling deployments — different nodes may pull different versions based on cache freshness
DC1005🟠 WARNINGAdd healthcheckService missing healthcheck blockDocker Compose health checks enable dependency ordering (depends_on with condition) and provide status to orchestration layers
DC1006ℹ️ INFOUse named volumesBind mount (./host/path:/container/path) detectedBind mounts tie the service to a specific host filesystem layout, preventing portability across environments and complicating backup strategies

Pass Score System

Each lint run produces a Pass Score (0–100) that quantifies overall quality:

Finding TypePoint DeductionInterpretation
🔴 ERROR−20 points eachCritical security or reliability issue — must be fixed
🟠 WARNING−5 points eachBest-practice deviation — should be addressed
ℹ️ INFO0 pointsAdvisory — consider for long-term improvement

Score thresholds:

  • Score ≥ 70 → Pass. Acceptable quality for most environments.
  • Score < 70 → Needs improvement. Review findings and remediate.
  • Any ERROR + Strict Mode → Run fails immediately, regardless of score.

Examples:

  • A Dockerfile with FROM python:latest (DL3000, ERROR), root user in final stage (DL3003, ERROR), missing HEALTHCHECK (DL3009, ERROR), and no USER directive (DL3001, WARNING) → score = 100 − 60 − 5 = 35 (Needs improvement)
  • The same file with five unpinned apt packages (DL3004, WARNING each) → score = 100 − 20 − 5 − 5 − 5 − 5 − 5 = 55 (Needs improvement)
  • A docker-compose file with privileged: true (DC1003, ERROR) in strict mode → score = 80 but run fails due to strict mode

Charge Events

The actor records platform usage through the following charge events:

EventWhen Charged
dockerfile-lintEach Dockerfile lint operation
compose-validateEach docker-compose validation operation
policy-checkEach strict-mode enforcement check
batch-lint(reserved) Future batch-linting support

Input Parameters

FieldTypeDefaultRequiredDescription
modeselectdockerfileNoLint scope: dockerfile, compose, or both
dockerfileContenttextareaYes*Full content of the Dockerfile to lint. Paste directly or leave blank when using dockerfilePath
dockerfilePathstringNoAlternative to dockerfileContent — path to a Dockerfile file on the same filesystem, a URL, or an Apify Key-Value Store key
composeContenttextareaYes**Full content of the docker-compose.yml file to lint. Required when mode is compose or both
strictModebooleanfalseNoWhen enabled, any ERROR-level finding causes the actor to report a failure (for CI/CD gate enforcement)

* Required unless dockerfilePath is provided and mode is dockerfile or both. ** Required when mode is compose or both.


Example Input

Example 1: Dockerfile Lint (mode: dockerfile)

{
"mode": "dockerfile",
"dockerfileContent": "FROM python:latest\nWORKDIR /app\nCOPY requirements.txt .\nRUN pip install -r requirements.txt\nCOPY . .\nCMD [\"python\", \"app.py\"]\n",
"strictMode": true
}

Example 2: Dockerfile Lint with Path

{
"mode": "dockerfile",
"dockerfilePath": "./path/to/Dockerfile",
"strictMode": false
}

Example 3: Dockerfile Lint with URL

{
"mode": "dockerfile",
"dockerfilePath": "https://raw.githubusercontent.com/example/repo/main/Dockerfile",
"strictMode": true
}

Example 4: Docker-Compose Lint (mode: compose)

{
"mode": "compose",
"composeContent": "services:\n web:\n image: nginx:latest\n ports:\n - \"80:80\"\n privileged: true\n api:\n image: myapp\n build: .\n",
"strictMode": true
}

Example 5: Lint Both (mode: both)

{
"mode": "both",
"dockerfileContent": "FROM node:20-alpine\nWORKDIR /app\nCOPY package*.json ./\nRUN npm install\nCOPY . .\nCMD [\"node\", \"server.js\"]\n",
"composeContent": "version: \"3.8\"\nservices:\n app:\n build: .\n image: my-app:1.0.0\n restart: unless-stopped\n healthcheck:\n test: [\"CMD\", \"curl\", \"-f\", \"http://localhost\"]\n interval: 30s\n timeout: 10s\n retries: 3\n deploy:\n resources:\n limits:\n memory: \"512M\"\n cpus: \"0.5\"\n",
"strictMode": false
}

Output Format

The actor pushes a single dataset item per run with the following structure:

{
"dockerfile": {
"findings": [
{
"id": "DL3000",
"severity": "ERROR",
"title": "Use specific base image tags (not 'latest')",
"description": "Base image uses 'latest' tag which leads to non-reproducible builds.",
"remediation": "Pin to a specific version tag (e.g., python:3.13-slim instead of python:latest).",
"line": 1,
"text": "FROM python:latest"
},
{
"id": "DL3003",
"severity": "ERROR",
"title": "No root user in final image",
"description": "Final stage should switch to non-root user via USER directive.",
"remediation": "Add 'USER nobody' or create a dedicated user at the end of your Dockerfile.",
"line": null,
"text": null,
"stage": "final"
},
{
"id": "DL3009",
"severity": "ERROR",
"title": "Add HEALTHCHECK instruction",
"description": "Production containers should have a HEALTHCHECK for orchestration.",
"remediation": "Add HEALTHCHECK instruction to your Dockerfile.",
"line": null,
"text": null
},
{
"id": "DL3001",
"severity": "WARNING",
"title": "No USER directive found",
"description": "Running containers as root is a security risk.",
"remediation": "Add a USER directive to run as non-root user.",
"line": null,
"text": null
}
],
"errorCount": 3,
"warningCount": 1,
"infoCount": 0,
"passScore": 35
},
"summary": {
"totalErrors": 3,
"totalWarnings": 1,
"overallPassScore": 35,
"reviewedAt": "2026-07-23T12:00:00"
}
}

Output Field Reference

FieldTypeDescription
dockerfile / composeobjectLint results for each mode that was run
[].findingsarrayList of rule violations found
[].findings[].idstringRule identifier (e.g., DL3000, DC1003)
[].findings[].severitystringERROR, WARNING, or INFO
[].findings[].titlestringShort rule summary
[].findings[].descriptionstringDetailed explanation of the issue
[].findings[].remediationstringActionable fix suggestion
[].findings[].linenumber or nullLine number in the Dockerfile (null for file-level checks)
[].findings[].textstring or nullOffending text excerpt (null for absence checks)
[].findings[].servicestring or nullService name for compose findings (null for Dockerfile rules)
[].errorCountnumberTotal ERROR-level findings
[].warningCountnumberTotal WARNING-level findings
[].infoCountnumberTotal INFO-level findings
[].passScorenumberPass score 0–100 for this mode
summary.totalErrorsnumberCombined errors across all modes
summary.totalWarningsnumberCombined warnings across all modes
summary.overallPassScorenumberOverall pass score 0–100
summary.reviewedAtstringISO 8601 timestamp of the lint run

Dataset Views

The actor's dataset includes three pre-configured views for convenient analysis:

ViewFields IncludedBest For
OverviewError/warning counts and pass scores across all modesDashboarding and trending
Errors OnlyAll ERROR-level findings with rule IDs and line numbersTriage sessions and incident response
Dockerfile FindingsAll Dockerfile-specific findings with line-level detailDeveloper feedback in CI/CD

Use Cases

  • CI/CD Pipeline Quality Gate — Plug the actor into GitHub Actions, GitLab CI, or Jenkins as a pre-deployment step. With strict mode enabled, any ERROR-level finding (root user, missing HEALTHCHECK, privileged compose service) blocks the pipeline and notifies the team. The pass score provides a quantitative quality metric that teams can target and trend over time.

  • Security Compliance Auditing — Enforce CIS Docker Benchmark Level 1 and Level 2 recommendations across your entire container fleet. The linter's DL3001 (USER directive), DL3009 (HEALTHCHECK), and DC1003 (privileged mode) rules map directly to CIS controls. Use the structured output to generate compliance reports for internal audits or customer security questionnaires.

  • Multi-Repository Batch Audit — When taking over a legacy codebase or preparing for a platform migration, run the linter against every Dockerfile across your microservice repositories. The pass score gives you an instant inventory of which services need attention, while individual findings tell engineers exactly what to fix. No need to clone and review each repo manually.

  • DevOps Onboarding & Standards Enforcement — Standardise container configuration quality across teams by integrating the linter into your code review workflow. New team members learn best practices through structured remediation guidance rather than tribal knowledge. The linter catches common mistakes — FROM latest, missing HEALTHCHECK, unbounded compose resources — before they reach the reviewer's inbox.

  • Kubernetes Readiness Validation — Ensure every container image destined for Kubernetes has proper HEALTHCHECK directives, runs as a non-root user, and uses pinned base images. The linter validates these requirements before the image is built and pushed to your registry, reducing the feedback loop from "CrashLoopBackOff in production" to "CI pipeline rejection in development."

  • Supply Chain Security Hardening — Pin base image tags, apt package versions, and pip packages to prevent supply chain attacks where a compromised latest tag or unpinned dependency introduces malicious code into your build pipeline. The linter's DL3000, DL3004, and DL3013 rules target exactly these vectors.

  • Dockerfile Refactoring & Modernisation — When migrating from single-stage to multi-stage builds or switching from Alpine to distroless base images, run the linter before and after the change to verify that best practices are maintained. The DL3003 (final stage root user) and DL3011 (multi-stage naming) rules catch common refactoring mistakes.

  • Cloud Migration & Containerisation Audits — As part of a lift-and-shift or re-platforming migration, audit all newly created Dockerfiles for security and operability issues. The linter's comprehensive rule set serves as an automated checklist that ensures containerised applications meet production readiness standards before they reach the cloud environment.