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.
openrouting — dockerfile explainer
$ explain Dockerfile! COPY copies the whole build context lowline 3fix: 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.
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.
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.