OWASP DockSec

Dockerfile from OWASP DockSec, an AI-assisted Dockerfile security tool — a real-world example, rewritten upstream on 2026-09-20. It now pins its tool versions and fails loudly on a bad download, but still fetches a binary and an archive with no checksum or signature check, runs as root, and executes a copied-in entrypoint script.

← Examples

Source: GitHub

9 issues foundHigh: 4Medium: 2Low: 3Recommendations: 2
DockerfileLines with findings are highlighted
SHA-256:
1FROM python:3.12-slimHigh
2ARG TRIVY_VERSION=0.74.0
3ARG HADOLINT_VERSION=2.15.1
4RUN apt-get update && apt-get install -y --no-install-recommends curl git && rm -rf /var/lib/apt/lists/*Medium
5RUN set -eux; arch="$(dpkg --print-architecture)"; case "$arch" in amd64) hadolint_arch='x86_64' ;; arm64) hadolint_arch='arm64' ;; *) echo "unsupported architecture: $arch" >&2; exit 1 ;; esac; curl -fsSL -o /usr/local/bin/hadolint "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-${hadolint_arch}"; chmod +x /usr/local/bin/hadolintHigh
6RUN set -eux; arch="$(dpkg --print-architecture)"; case "$arch" in amd64) trivy_arch='Linux-64bit' ;; arm64) trivy_arch='Linux-ARM64' ;; *) echo "unsupported architecture: $arch" >&2; exit 1 ;; esac; curl -fsSL -o /tmp/trivy.tar.gz "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_${trivy_arch}.tar.gz"; tar -xzf /tmp/trivy.tar.gz -C /usr/local/bin trivy; rm -f /tmp/trivy.tar.gzHigh
7RUN trivy --version && hadolint --version
8WORKDIR /src
9COPY . .Medium
10RUN pip install --no-cache-dir ".[ai]"Low
11RUN docksec --version
12WORKDIR /github/workspace
13RUN rm -rf /src
14COPY entrypoint.sh /entrypoint.sh
15RUN chmod +x /entrypoint.sh
16ENTRYPOINT ["/entrypoint.sh"]Low
Findings
9 issues found
RUN set -eux \
  ; arch="$(dpkg --print-architecture)" \
  ; case "$arch" in amd64) hadolint_arch='x86_64' \
  ; arm64) hadolint_arch='arm64' \
  ; *) echo "unsupported architecture: $arch" >&2 \
  ; exit 1 \
  ; esac \
  ; curl -fsSL -o /usr/local/bin/hadolint "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-${hadolint_arch}" \
  ; chmod +x /usr/local/bin/hadolint
Unverified executable downloaded at build time
A file is downloaded at build time (curl/wget) and made executable — written into a bin directory or chmod +x'd — without verifying its integrity. The contents are unverified, so a compromised or malicious source — or a silently changed artifact — substitutes an arbitrary executable that then runs with build-time (and often runtime) privileges. The risk is greatest when the URL is unpinned (e.g. a /latest/ release URL), since the artifact can change at any time. Pin a specific version and verify a published SHA-256 checksum or a GPG/cosign signature before use, or COPY a pre-verified binary into the image.
# Pin a version, verify the checksum, then install RUN curl -fsSL -o /tmp/hadolint \ https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 \ && echo "<sha256> /tmp/hadolint" | sha256sum -c \ && install -m 0755 /tmp/hadolint /usr/local/bin/hadolint
HighPermissions
RUN set -eux \
  ; arch="$(dpkg --print-architecture)" \
  ; case "$arch" in amd64) trivy_arch='Linux-64bit' \
  ; arm64) trivy_arch='Linux-ARM64' \
  ; *) echo "unsupported architecture: $arch" >&2 \
  ; exit 1 \
  ; esac \
  ; curl -fsSL -o /tmp/trivy.tar.gz "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_${trivy_arch}.tar.gz" \
  ; tar -xzf /tmp/trivy.tar.gz -C /usr/local/bin trivy \
  ; rm -f /tmp/trivy.tar.gz
Unverified archive downloaded and extracted at build time
A remote archive (zip/tar) is downloaded at build time and unpacked into the image without verifying its integrity. The extracted contents usually become part of the runtime image or are executed later (for example as the ENTRYPOINT), so a compromised or substituted archive — or a download from a defunct or hijacked host — introduces arbitrary files into the image. The risk is greatest when the version or URL is resolved dynamically (e.g. from a remote current.txt or an ENV-built URL), since the artifact can change at any time. Pin a specific version and verify a published SHA-256 checksum or a GPG/cosign signature before extracting.
HighPermissions
FROM python:3.12-slim
High CVEs in base image
The base image has one or more high-severity CVEs according to Docker Scout, and no critical ones. High vulnerabilities are often exploitable and may allow privilege escalation or data exposure. Update to a patched image version or switch to a more secure base image. Note: CVE data is sourced from Docker Scout at the time of the last data rebuild — coverage is not guaranteed to be complete, and a clean result does not confirm the image is free of CVEs.
HighBase Image
Container user
User root
The final container is running under the context of the root user.
# Create a dedicated non-root user and switch to it before CMD/ENTRYPOINT RUN useradd --create-home --shell /bin/bash appuser USER appuser
HighUser
RUN apt-get update \
  && apt-get install -y --no-install-recommends curl git \
  && rm -rf /var/lib/apt/lists/*
Apt-family install, but no upgrade
An apt-family tool (apt, apt-get, aptitude, dpkg) is used to install packages but upgrade was not called first to patch existing packages.
RUN apt-get update && apt-get upgrade -y \ && apt-get install -y --no-install-recommends <packages> \ && rm -rf /var/lib/apt/lists/*
MediumPackage Manager
COPY . .
Wildcard COPY
Using COPY with a wildcard can introduce unnecessary files into the image.
COPY src/ /app/src/ # or target a specific file COPY config.json /app/config.json
MediumFile Copy
FROM python:3.12-slim
FROM without image digest
The base image is referenced by tag rather than by digest. Tags are mutable — the same tag can be silently updated to point to a different image. Pinning to a digest (e.g. image:tag@sha256:...) guarantees you always build from exactly the image you reviewed. If you rebuild frequently with docker build --pull, the freshness risk is lower — though supply-chain reproducibility still benefits from digest pinning. Note: digest-pinning fixes the image layer but does not protect against newly-discovered CVEs in that layer — vulnerability scanning should still be performed regularly even when digests are in use.
LowBase Image
ENTRYPOINT ["/entrypoint.sh"]
Executes a copied-in script not analysed by DockerSec
A shell script is copied into the image (COPY/ADD) and then executed by a RUN, ENTRYPOINT, or CMD instruction. DockerSec analyses the Dockerfile only; the script contents are not inspected, so security-relevant operations inside it (package installs, credential handling, network configuration, privilege changes) are not covered by this scan. There is latent risk here: review the script manually. Where practical, inline the script logic into the Dockerfile so it can be analysed, or keep the script minimal and audited.
Low
RUN pip install --no-cache-dir ".[ai]"
pip used without upgrading pip itself
pip is used in this stage but pip itself is never upgraded. An outdated pip may resolve packages against a stale index and may itself contain known vulnerabilities. Add pip install --upgrade pip (or pip install -U pip) before installing other packages.
LowPackage Manager

RUN apt-get update \
  && apt-get install -y --no-install-recommends curl git \
  && rm -rf /var/lib/apt/lists/*
apt-get install without version pinning
apt-get install is used without pinning package versions. Without a version constraint (e.g. nginx=1.18.0-0ubuntu1), apt will install whatever is current in the package index at build time, making the build non-reproducible and potentially installing an unexpected newer version on a future rebuild. Pin package versions to ensure consistent, reproducible builds: apt-get install -y nginx=1.18.0-0ubuntu1.
Package Manager
No HEALTHCHECK defined
No HEALTHCHECK defined in final stage
The final image stage does not define a HEALTHCHECK instruction. Without one, container orchestrators and the Docker daemon cannot distinguish a running container from one that is alive but unhealthy (deadlocked, crashed dependencies, etc.), increasing the risk of traffic being routed to a broken container. Add a HEALTHCHECK CMD instruction that tests whether the application is functioning correctly. Note: if the base image already defines a HEALTHCHECK it will be inherited, but this cannot be verified from the Dockerfile alone.