October 1, 2026 路 #15
The dotenv that went to the registry
The app reads configuration from the environment at runtime. Why is this image still a secret leak?
FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN rm -f .env
USER node
CMD ["node", "server.js"]Next puzzle in UTC
One try. The first answer sticks.
How to fix it
A later RUN rm does not erase the COPY layer. Exclude .env, .git, and keys with .dockerignore so they never enter the build context.
COPY . . copies the build context, which is usually the whole directory Docker was pointed at. A .env sitting next to the Dockerfile is now a layer. RUN rm -f .env adds another layer on top. The file is gone from the final directory listing and still present in the image history.
The same copy also drags in .git, local cloud credentials, and test fixtures you did not mean to publish.
Fix
Add a .dockerignore before you worry about the Dockerfile:
.env
.env.*
.git
**/*.pem
Then copy only what the runtime needs. Keep real configuration in the orchestrator. The image should start with an empty environment and fail fast when a required variable is missing, which is a better bug than booting with a developer laptop's database URL.