All integrations

Hadolint Dockerfile check Integration with DefectDojo

Hadolint Dockerfile check Integration with DefectDojo

Hadolint is an open source Dockerfile linter written in Haskell and maintained by the hadolint project on GitHub. It parses a Dockerfile into a syntax tree and checks it against its own rules (codes beginning DL), such as pinning package and base image versions, avoiding sudo, setting a non-root USER, and preferring COPY over ADD. It also runs ShellCheck on the shell commands inside RUN instructions (codes beginning SC). Each result has a level of error, warning, info, or style, and Hadolint can write results in several formats, including JSON, which DefectDojo imports with its Hadolint Dockerfile check scan type.

Hadolint Dockerfile check Integration with DefectDojo

We lint every Dockerfile with Hadolint because it catches build mistakes before an image exists: an unpinned base image, a missing USER, a package install that pulls whatever version is current today. In a pull request, that output gets fixed or waved through and then forgotten. Importing Hadolint JSON into DefectDojo gives each result a Finding on the Asset that owns the Dockerfile, with file and line, so we can see which repositories keep building root containers and track the cleanup like any other security work.

Why Hadolint Matters

Dockerfiles decide the starting point of every container's security, and they are short enough that small mistakes have outsized effects.

  • Unpinned versions make builds non-reproducible and can silently pull in vulnerable packages.
  • Running as root by default widens the impact of any container escape or application compromise.
  • Shell mistakes inside RUN lines, caught by ShellCheck, can hide failed commands and leave images half-built.
  • Hadolint runs in seconds without building the image, so it fits into pre-commit hooks and every CI job.
  • Its output is per run. Without a tracking system, there is no history of which issues were fixed or accepted.

Advantages of This Integration

What we gained by importing Hadolint results into DefectDojo:

  • Findings tied to code. Each finding carries the Dockerfile path and line, so engineers can go straight to the instruction.
  • Stable across runs. DefectDojo hashes Hadolint findings on title, CWE, line, file path, and description, so an unchanged Dockerfile reimports without duplicates.
  • Fix tracking. Reimporting each run into the same Test mitigates rules that no longer fire and adds new ones.
  • Accepted exceptions recorded. A rule that doesn't fit a particular image can be risk-accepted with a reason and an expiry, which is easier to audit than scattered ignore comments.
  • Build hygiene next to image scanning. Hadolint findings sit on the same Asset as container image scan results, which shows whether problems start in the Dockerfile or the base image.

How This Integration Works

DefectDojo imports Hadolint output with the Hadolint Dockerfile check scan type, which reads Hadolint's JSON format.

1. Run Hadolint with JSON output. Pass one or more Dockerfiles:

hadolint -f json Dockerfile docker/worker.Dockerfile > hadolint-report.json

The JSON is a list of results, each with the file, line, column, rule code, message, and level. Results from several Dockerfiles can go in one report because each result names its file.

Hadolint exits with a failure status when rules are violated. In a pipeline, either add --no-fail to the reporting run or let the import step run even when the lint step fails, so violations still reach DefectDojo. If you want the build to fail as well, gate it separately, for example with --failure-threshold error.

2. Import the report. In the UI, open the Engagement, choose Import Scan Results, select Hadolint Dockerfile check, and upload the file. To automate, use the import API in Community Edition or DefectDojo Pro:

curl "https://YOUR_INSTANCE/api/v2/import-scan/" \
  -H "Authorization: Token $DD_API_TOKEN" \
  -F "scan_type=Hadolint Dockerfile check" \
  -F "file=@hadolint-report.json" \
  -F "product_name=payments-api" \
  -F "engagement_name=CI" \
  -F "auto_create_context=true"

DefectDojo Pro users can run the same import with Universal Importer:

universal-importer import \
  --defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/" \
  --scan-type "Hadolint Dockerfile check" \
  --report-path "./hadolint-report.json" \
  --product-name "payments-api" \
  --engagement-name "CI" \
  --auto-create-context

3. Reimport on each change. Send later reports to /api/v2/reimport-scan/ against the same Test so fixed instructions close.

Data Granularity: What Gets Imported

DefectDojo Field Source in Hadolint JSON Notes
Title code, message Formatted as code: message, for example a DL or SC rule and its text
Severity level error is Critical; warning is High; info, style, or a missing level is Info
Description code, message Rule code and the message text
File Path file The Dockerfile path as passed to Hadolint
Line line Line of the instruction
Within-report duplicates line, column, code, file Identical results at the same position collapse into one finding
Finding type Static All findings are static
Deduplication Hashcode Title, CWE, line, file path, description

Hadolint doesn't provide CWE, references, or remediation text in its JSON. The rule code links to the rule's page in the Hadolint (DL) or ShellCheck (SC) wiki, which explains the fix.

Use Cases

In a CI/CD pipeline: Each merge to the main branch runs Hadolint on every Dockerfile in the repository and reimports into one Test. New Critical findings (Hadolint errors) get an owner and an SLA, and fixed ones close on the next run.

Base image governance: A platform team imports Hadolint results for its shared base image Dockerfiles into one Asset and uses DefectDojo to show application teams which issues come from the base and which from their own instructions.

Rolling out stricter rules: Teams new to Hadolint import the first results, risk-accept the rules they plan to address later with expiry dates, and fix the high-value ones such as running as root right away.

Reporting across repositories: Security leads compare open Hadolint findings across Assets to find the repositories that still use unpinned base images or run as root.

Operational Tips

  • The severity mapping is strict: every Hadolint warning becomes High. Rules like version pinning will land as High, so review your SLA targets for this scan type or adjust severity during triage.
  • Use minimum_severity=High to keep info and style results out if your team only wants to work errors and warnings.
  • Line number is part of the hashcode. Adding lines above an existing issue moves it, and reimport may treat it as new, so close the old finding when that happens.
  • Run Hadolint with the same file paths each time (relative to the repository root), since file path is also part of the hashcode.
  • Keep a .hadolint.yaml in the repository for team-wide ignores, and use DefectDojo risk acceptance for exceptions that need a recorded reason and review date.
  • Tag imports with the repository name to filter Dockerfile findings in reports.