RSTR-IAC-002 — Dockerfile USER root
Summary
A Dockerfile sets USER root explicitly (or omits USER entirely)
in the final stage, so the container's PID 1 — and every application
process — runs as root. If anything inside the container escapes
(kernel CVE, mounted-host volume, privileged docker socket), the
attacker lands as root on the host.
Severity
High.
Languages
Dockerfiles, Containerfiles.
What rastray flags
FROM alpine:3.20
USER root # ← flagged
CMD ["./server"]
What rastray deliberately does not flag
- Final-stage
USER nobody/USER 1001/ any non-root user. - Multi-stage builds where the builder stage uses root but the final runtime stage drops privileges.
How to fix it
Create a non-root user and switch to it in the runtime stage:
FROM alpine:3.20
RUN addgroup -S app && adduser -S app -G app
USER app
WORKDIR /home/app
COPY --chown=app:app . .
CMD ["./server"]
If you genuinely need root for an init step (writing to /etc,
binding a privileged port), do that in a builder stage or via
capabilities — not by leaving the runtime process as root:
# install root-only stuff in builder stage
FROM alpine:3.20 AS builder
RUN ... # root operations
FROM alpine:3.20
USER app
COPY --from=builder /opt/app /opt/app
For privileged ports (<1024) in production, terminate at a load balancer / ingress and bind the app to a high port.