FROM node:latest
WORKDIR /app
COPY . .
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc && npm install
EXPOSE 3000
CMD ["node", "server.js"]
There are five problems.
node:latestisn't pinned. It changes without warning, and the full image has many extra packages, each a possible CVE. Use a pinned, small base such asnode:22-slimor a distroless image, ideally pinned by digest.COPY . .copies everything. Without a.dockerignore, the image gets.envfiles,.git, localnode_modulesand any keys in the folder.- The npm token leaks. Build arguments show up in the image history (
docker history). The.npmrcfile also stays in that image layer. Use a BuildKit secret mount instead:RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci. npm installinstalls too much. Usenpm ci --omit=devfor exact versions with no dev tools. A multi-stage build keeps build tools and source files out of the final image.- It runs as root. There is no
USERline. If an attacker breaks in, root makes escaping the container easier. The official Node image has anodeuser, so addUSER node.
Also scan the image in CI. At runtime, use a read-only file system and drop Linux capabilities you don't need.
- Pin a small base image instead of
node:latest. - Add a
.dockerignoreso.envfiles and.gitaren't copied. - Build arguments and files in layers leak secrets, so use BuildKit secret mounts.
- Use
npm ci --omit=devand multi-stage builds. - Run as a non-root user with
USER node.
Read more