Dockerfile check · low

COPY . copies the whole build context

COPY . . copies everything in the build context into the image: source, but also .git, local .env files, test data, editor files and anything else in the directory, unless a .dockerignore excludes it. Those files then live in an image layer that anyone who pulls the image can read. Copy specific paths, or keep a strict .dockerignore, ideally an allow-list.

$ explain Dockerfile
! COPY copies the whole build context low
line 3
fix: see below
$ 

What the free Dockerfile explainer reports on the risky example below.

Why it matters

What ends up in the image depends on what happens to be in the directory at build time. A developer's local .env or a credentials file left in the project is copied without anyone noticing.

.git can contain the full history of the repository, including files and secrets that were removed from the current version.

The explainer only sees the Dockerfile, not your .dockerignore, so it flags COPY . , COPY ./ and COPY * at low severity as a reminder to check it.

Risky and safer Dockerfile

RiskyDockerfile
FROM node:22.11-slim
WORKDIR /app
COPY . .
RUN npm ci --omit=dev
USER 10001
HEALTHCHECK CMD ["node", "src/healthcheck.js"]
CMD ["node", "src/server.js"]
SaferDockerfile
FROM node:22.11-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src ./src
USER 10001
HEALTHCHECK CMD ["node", "src/healthcheck.js"]
CMD ["node", "src/server.js"]

How to fix it

  • Copy only the paths the image needs, e.g. COPY package.json package-lock.json ./ then COPY src ./src. Copying the dependency manifests first also improves layer caching.
  • If you keep COPY . ., add a .dockerignore. An allow-list is safest: a line with * to exclude everything, then !src and !package*.json to add back what the image needs.
  • At minimum, exclude .git, .env*, keys and local credential files.

When it's acceptable

  • Projects with a strict .dockerignore allow-list. The explainer can't see it, so the low-severity reminder still appears.
  • Build stages whose output is copied into a slim final stage with COPY --from, as long as the final stage copies only specific build outputs.

Check your own Dockerfile

The risky example is loaded below. Paste your own file to check it for this and every other Dockerfile rule. It runs in your browser; nothing is uploaded.

Dockerfile

Parsed in your browser. Nothing is uploaded.

Explanation

1 stage7 instructions2 low

Stage 0node:22.11-slim

  • Docs for FROM (opens in a new tab)

    Starts from the base image node, tag 22.11-slim.

    A version tag can be re-pushed to different content; only a digest is immutable. This applies to every tagged FROM in the file.

    Safer: Pin the digest as well (image:tag@sha256:<digest>) and let a bot open pull requests when it changes.

  • Docs for WORKDIR (opens in a new tab)

    Sets the working directory to /app for later instructions and the container. It is created if it does not exist.

  • Docs for COPY (opens in a new tab)

    Copies . from your build context to . in the image.

    Copying the whole context includes .git, local .env files and anything else in the directory unless a .dockerignore excludes it. We can't see your .dockerignore here.

    Safer: Add a .dockerignore (an allow-list is safest: exclude everything, then add back what the image needs) or copy only the paths you need.

  • Docs for RUN (opens in a new tab)

    Runs npm ci --omit=dev while building the image and saves the result as a new layer.

  • Docs for USER (opens in a new tab)

    Runs later instructions and the container's process as user 10001.

  • Docs for HEALTHCHECK (opens in a new tab)

    Runs node src/healthcheck.js to check the container is healthy.

  • Docs for CMD (opens in a new tab)

    Sets the default command to node src/server.js. It runs when the container starts, and anything passed to docker run replaces it.

Questions

Does COPY . . include the .git folder?

Yes, unless .dockerignore excludes it. The whole build context is copied, hidden files included.

How do I write a .dockerignore allow-list?

Start with a line containing * to exclude everything, then add exceptions with !, for example !src and !package*.json. Only the excepted paths are sent to the build.

Can the Dockerfile explainer read my .dockerignore?

No. It analyses the one Dockerfile you paste, in your browser, so it flags whole-context copies as a low-severity reminder rather than a confirmed leak.