Because container root is the same user as host root. By default, the process in a container runs as root, which is UID 0 (user ID 0). This is the same UID as root on the host. The only exceptions are when you use user namespaces (a feature that maps container users to different host users) or rootless mode.
Imagine an attacker breaks into your app. Then they escape the container through a kernel bug, a runtime bug or a careless mount. Now they are root on the host. A non-root user also limits what the attacker can change inside the container.
How to do it for a Node app:
- The official Node images include a
nodeuser. AddUSER nodebeforeCMD. - Files you
COPYare owned by root. UseCOPY --chown=node:nodeonly for paths the app must write to. - Listen on a high port such as 3000 or 8080, and map it to the port you want.
Why a high port? Traditionally, a non-root user cannot bind ports below 1024. Docker 20.10 and later relaxes this inside containers by default. Older Docker versions and some other runtimes, such as some Kubernetes setups, do not. So a high port works everywhere.
- By default, root in a container is UID 0 on the host.
- A non-root user limits the damage after an attack or a container escape.
- Official Node images have a
nodeuser, so addUSER node. - Use
COPY --chownfor paths the app must write to. - Listen on a high port such as 3000.