Dockerfile Linter — Security & best-practices checker
Pricing
from $0.02 / dockerfile lint
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
Maintained by CommunityActor 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?
| Persona | Why this actor matters |
|---|---|
| DevSecOps Engineer | Enforce security baselines across every container image built in the organisation. Block PRs with root containers or unpinned base images before they merge. |
| Platform / SRE Engineer | Ensure every service in the platform has HEALTHCHECK, resource limits, and restart policies defined. Catch privileged: true usage before it reaches production. |
| Software Engineer | Get instant feedback on Dockerfile quality during development. Learn best practices through structured remediation suggestions without memorising rule numbers. |
| CI/CD Pipeline Architect | Drop 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 Auditor | Batch-audit Dockerfiles across microservices repositories in a single run. Generate compliance evidence for CIS Docker Benchmark adherence. |
| DevOps Onboarding Lead | Standardise 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: trueand 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)
| ID | Severity | Rule | What It Checks | Why It Matters |
|---|---|---|---|---|
| DL3000 | 🔴 ERROR | Pin base image tags | FROM python:latest detected | latest changes silently — breaks reproducibility and can introduce breaking OS/package changes mid-release |
| DL3001 | 🟠 WARNING | Add USER directive | No USER line found in the entire Dockerfile | Root containers are a top-10 container security risk. If compromised, the attacker has full host-level access (depending on runtime) |
| DL3002 | 🟠 WARNING | Prefer COPY over ADD | ADD instruction used for local files | ADD has hidden behaviours (automatic tar extraction, remote URL fetching) that create opaque builds and potential security surprises |
| DL3003 | 🔴 ERROR | No root user in final stage | Final build stage lacks a USER directive | Even if earlier stages have users, the final running image defaults to root unless explicitly switched. A common oversight in multi-stage builds |
| DL3004 | 🟠 WARNING | Pin apt package versions | apt-get install curl (no =version) | Unpinned packages produce different results on different build dates. Pin versions for deterministic, auditable builds |
| DL3005 | 🟠 WARNING | Combine apt-get update && install | Separate RUN apt-get update and RUN apt-get install | Separate instructions create an extra layer and risk caching a stale apt-get update while picking up newer packages — a security gap |
| DL3006 | ℹ️ INFO | Remove apt lists after install | Missing 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 | 🟠 WARNING | Avoid sudo in RUN | RUN sudo ... pattern detected | sudo inside a Dockerfile indicates the container is running as root or has inconsistent user switching. Either way, the permission model needs review |
| DL3008 | 🟠 WARNING | Use WORKDIR not RUN cd | RUN cd /app && ... pattern | RUN cd only affects that single shell command. WORKDIR sets the working directory for all subsequent instructions and is self-documenting |
| DL3009 | 🔴 ERROR | Add HEALTHCHECK instruction | No HEALTHCHECK found in the Dockerfile | Orchestrators (Kubernetes, Docker Swarm, ECS) rely on HEALTHCHECK for traffic routing and self-healing. Missing it means downtime isn't detected automatically |
| DL3010 | ℹ️ INFO | Use COPY --chown | COPY without --chown flag | Setting ownership at copy time eliminates the need for a separate RUN chown layer, reducing image size and build time |
| DL3011 | 🟠 WARNING | Name multi-stage build stages | FROM ... AS missing in multi-stage builds | Unnamed stages make the Dockerfile harder to read and prevent --target selective builds |
| DL3013 | 🟠 WARNING | Use pip --no-cache-dir | pip install without --no-cache-dir | Pip cache adds 10–100 MB per layer. Add --no-cache-dir to keep images lean |
| DL3015 | 🟠 WARNING | Use --no-install-recommends | apt-get install without --no-install-recommends | Recommends packages add substantial image bloat — often doubling the layer size for utility packages |
Docker-Compose Rules — DC1000 to DC1006 (7 checks)
| ID | Severity | Rule | What It Checks | Why It Matters |
|---|---|---|---|---|
| DC1000 | ℹ️ INFO | Add version field | Compose file missing version | While recent Docker Compose v2 treats version as optional, specifying it ensures compatibility across different Docker Engine versions and CI runners |
| DC1001 | 🟠 WARNING | Define restart policy | Service missing restart configuration | Without a restart policy, a crashed or OOM-killed service stays down until manually restarted. Production services should use unless-stopped or always |
| DC1002 | 🟠 WARNING | Set resource limits | Service missing deploy.resources.limits | Unbounded services can consume all host memory or CPU, starving sibling containers and triggering OOM kills across the node |
| DC1003 | 🔴 ERROR | Avoid privileged mode | Service has privileged: true | Privileged 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 | 🟠 WARNING | Pin image tags | Service uses image: myapp or :latest | Unpinned images break rolling deployments — different nodes may pull different versions based on cache freshness |
| DC1005 | 🟠 WARNING | Add healthcheck | Service missing healthcheck block | Docker Compose health checks enable dependency ordering (depends_on with condition) and provide status to orchestration layers |
| DC1006 | ℹ️ INFO | Use named volumes | Bind mount (./host/path:/container/path) detected | Bind 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 Type | Point Deduction | Interpretation |
|---|---|---|
| 🔴 ERROR | −20 points each | Critical security or reliability issue — must be fixed |
| 🟠 WARNING | −5 points each | Best-practice deviation — should be addressed |
| ℹ️ INFO | 0 points | Advisory — 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 noUSERdirective (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:
| Event | When Charged |
|---|---|
dockerfile-lint | Each Dockerfile lint operation |
compose-validate | Each docker-compose validation operation |
policy-check | Each strict-mode enforcement check |
batch-lint | (reserved) Future batch-linting support |
Input Parameters
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
mode | select | dockerfile | No | Lint scope: dockerfile, compose, or both |
dockerfileContent | textarea | — | Yes* | Full content of the Dockerfile to lint. Paste directly or leave blank when using dockerfilePath |
dockerfilePath | string | — | No | Alternative to dockerfileContent — path to a Dockerfile file on the same filesystem, a URL, or an Apify Key-Value Store key |
composeContent | textarea | — | Yes** | Full content of the docker-compose.yml file to lint. Required when mode is compose or both |
strictMode | boolean | false | No | When 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
| Field | Type | Description |
|---|---|---|
dockerfile / compose | object | Lint results for each mode that was run |
[].findings | array | List of rule violations found |
[].findings[].id | string | Rule identifier (e.g., DL3000, DC1003) |
[].findings[].severity | string | ERROR, WARNING, or INFO |
[].findings[].title | string | Short rule summary |
[].findings[].description | string | Detailed explanation of the issue |
[].findings[].remediation | string | Actionable fix suggestion |
[].findings[].line | number or null | Line number in the Dockerfile (null for file-level checks) |
[].findings[].text | string or null | Offending text excerpt (null for absence checks) |
[].findings[].service | string or null | Service name for compose findings (null for Dockerfile rules) |
[].errorCount | number | Total ERROR-level findings |
[].warningCount | number | Total WARNING-level findings |
[].infoCount | number | Total INFO-level findings |
[].passScore | number | Pass score 0–100 for this mode |
summary.totalErrors | number | Combined errors across all modes |
summary.totalWarnings | number | Combined warnings across all modes |
summary.overallPassScore | number | Overall pass score 0–100 |
summary.reviewedAt | string | ISO 8601 timestamp of the lint run |
Dataset Views
The actor's dataset includes three pre-configured views for convenient analysis:
| View | Fields Included | Best For |
|---|---|---|
| Overview | Error/warning counts and pass scores across all modes | Dashboarding and trending |
| Errors Only | All ERROR-level findings with rule IDs and line numbers | Triage sessions and incident response |
| Dockerfile Findings | All Dockerfile-specific findings with line-level detail | Developer 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
latesttag 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.