Skip to main content
DevOps Insightsguides & answers

Docker

What is wrong with this Dockerfile?

Two mistakes here are permanent rather than merely bad. COPY .env cannot be undone — deleting the file in a later step leaves it in the layer, extractable by anyone who can pull the image. And the base image decides most of the CVE count a scanner will ever report about you.

Every finding says what actually goes wrong, points at the line, and where it maps to a named CI/CD risk it links there — a copied secret to credential hygiene, an unguarded package install to dependency chain abuse.

Runs in your browser · nothing is uploaded, stored or logged

Why this runs in your browser

A Dockerfile names your internal registries, build arguments and base images. That is real detail about your infrastructure, and this site has no reason to receive it — so it does not. The analysis is a pure function running on this page; there is no request to make, nothing is stored, and nothing is logged.

It also makes the tool safe by construction rather than by promise. Input that never reaches a server cannot be executed by one, and nothing here evaluates your build instructions as anything other than text.

Related

What a Dockerfile builds

A Dockerfile is the recipe for a container image. Each instruction adds a layer, and the layers stack into the filesystem your container starts with.

The consequence that surprises people is that layers are permanent. A file added by one instruction and deleted by a later one is still in the image: the deletion is a new layer recording its absence, not an edit to the layer that holds it. Anyone with the image can read it back.

Using it

Paste a Dockerfile. Findings point at the instruction and explain the consequence — a secret that survives in a layer, a base image that is not pinned, a process running as root, a script piped straight from the network into a shell.

As with any static read, some findings are acceptable in context. Running as root in a build stage that is discarded is fine; running as root in the final stage usually is not.

What this checks

  • Build hygiene and security issues in a Dockerfile you paste: running as root, untagged or :latest base images, a secrets file copied into the image, piping a download into a shell, and layer order that defeats the cache.

What it cannot know

  • Whether the image builds, how large it is, or which vulnerabilities its packages contain.

Check it for real

docker build --check .

Runs Docker's own build checks without building. Requires Buildx 0.15.0 or later; a vulnerability scanner is a separate step. Docker: build checks

Pinning, and the layer that keeps your secret

To keep a credential out of an image, it has to never enter a layer: use a build secret mount (--mount=type=secret) or fetch it at runtime. Adding then removing it does not work, and neither does ARG, which is recorded in the image's build metadata. Multi-stage builds help only when the secret never appears in the stage you actually ship.

Pinning has three levels, and they are not the same promise. :latest is whatever was pushed most recently. A version tag like :3.12 is a moving target — the maintainer repoints it at each patch release, which is usually what you want for security fixes. A digest (@sha256:…) is exactly one image forever, which makes the build reproducible and means you get no fixes until you change it. Reproducibility and patching genuinely pull against each other here; digests plus automated bumps is the usual resolution.

Terms used here (1)

Short definitions for the vocabulary on this page, in case any of it is new. Each links to the full entry.

Image
A read-only template used to create containers. A container image packages application code, runtime, libraries, and dependencies into a single artifact that can be versioned, shared via registries, and run identically on any compatible host.

All 59 terms in the glossary

Questions people ask about this

Why does it matter that a secret is in a layer?

Because layers are the image. Anyone who can pull the image can read it back with docker history or by unpacking the layer, and deleting the file in a later instruction does not remove it from the earlier one — it only hides it from the final filesystem. A secret that reached a layer has to be rotated, not edited out.

Why avoid running as root in a container?

A container is not a security boundary in the way a virtual machine is: root inside is still uid 0 on the host kernel, so a container escape starts from a much stronger position. Adding a USER instruction costs two lines and removes the easiest step of that chain.

What is wrong with a floating base image tag?

FROM node:20 resolves to whatever that tag points at today, so the same Dockerfile builds a different image next week and a build that worked yesterday can fail for reasons nothing in your repository explains. Pinning to a digest makes the build reproducible; pinning to a patch version is the usual compromise.

Does this send my Dockerfile anywhere?

No. The analysis runs in your browser — the rules are shipped as part of the page and applied locally, with no request carrying your file. That is a property of how it is built rather than a promise: there is no endpoint for it to post to.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it