no-root-user
Docker containers run as root by default. How to add a non-root USER to your Dockerfile and why it matters for container security.
On this page
Unless a Dockerfile says otherwise, every process in the container runs as root. Most images never say otherwise: there is no USER instruction, so the app inherits root from the base image. This rule flags any Dockerfile whose final stage still runs as root — including the case where a USER instruction exists but sets root or UID 0.
What the rule catches
FROM node:22-slim
WORKDIR /app
COPY . .
RUN npm ci
CMD ["node", "server.js"]Scanning this file reports:
⚠ WARN [docker-doctor/no-root-user]
The container runs as root. Running as root allows potential container breakout vulnerabilities.Why it matters
A container is not a security boundary on its own. If an attacker gets code execution inside a root container — through your app, a dependency, or a supply-chain compromise — they hold root on any file or volume the container can reach, and any kernel or runtime vulnerability becomes a path to root on the host. Dropping to an unprivileged user turns most of those escalations into dead ends, which is why it is the first hardening step every container security guide agrees on.
How to fix it
Add a non-root user (e.g., USER node or USER 1000) to improve security.
FROM node:22-slim
WORKDIR /app
COPY . .
RUN npm ci
USER node
CMD ["node", "server.js"]Official language images usually ship a ready-made unprivileged user: node in the Node.js images, nobody almost everywhere. If your base image has none, create one:
RUN useradd --no-log-init -r appuser
USER appuserSwitch users after the instructions that need root (package installs, chown), and remember that USER resets to root at every new FROM — the final stage needs its own USER line. If the app must bind a port below 1024, listen on a high port instead and map it (-p 80:8080).
Runtime variants of Docker Hardened Images (the dhi.io registry) default to a nonroot user, so this rule does not report them. A -dev variant in the final stage still reports.
Rule details
- Rule key —
docker-doctor/no-root-user - Category — Security
- Default severity —
warning - Applies to — Dockerfiles
Explain this rule from the CLI:
npx @docker-doctor/cli@latest rules explain docker-doctor/no-root-userChange its severity — or turn it off — in your config file:
// docker-doctor.config.ts
export default {
rules: {
"docker-doctor/no-root-user": "off",
},
};Severity affects the health score: error findings cost more points than warning, and info costs the least.