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.

References