Containers running as root (UID 0) violate the principle of least privilege (NIST 800-53 AC-6, CWE-250) and collapse the host boundary if any container escape vulnerability is exploited. A root container with a kernel exploit gains full control of the host node — every other workload on that node is compromised. CIS Docker 4.1 and CIS Kubernetes 5.2.6 both mandate non-root execution. The blast radius of a runtime compromise is bounded only when the container process has no privilege to exercise outside its own namespace.
Critical because a container running as root combined with any container-escape vulnerability grants full host node access, compromising all co-located workloads.
Add a dedicated unprivileged user in Dockerfile and enforce it in Kubernetes securityContext. In Dockerfile:
RUN useradd -m -u 1001 appuser
USER appuser
In your Kubernetes Deployment manifest (k8s/deployment.yaml):
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
For distroless images that have no useradd, set USER 65532 (the nonroot user built into distroless). The UID must exceed 1000 to avoid collision with system accounts.
ID: infrastructure-hardening.container-image-security.non-root-user
Severity: critical
What to look for: Count every Dockerfile and Kubernetes Deployment/StatefulSet manifest. For each, check whether a non-root user is configured — a USER directive with UID above 1000 in Dockerfiles, or securityContext.runAsNonRoot: true with runAsUser above 1000 in Kubernetes manifests.
Pass criteria: Every Dockerfile includes a USER directive specifying a non-root user with UID above 1000, and 100% of Kubernetes Deployment or StatefulSet manifests include securityContext.runAsNonRoot: true with explicit runAsUser above 1000. Report the ratio: "X of Y Dockerfiles and Z of W manifests enforce non-root."
Fail criteria: Any Dockerfile runs as root or omits the USER directive (which defaults to root), or any Kubernetes manifest lacks runAsNonRoot: true.
Do NOT pass when: A USER directive is present but specifies UID 0 (root) or a UID below 1000 — the user must be truly unprivileged.
Skip (N/A) when: The project does not have containerization.
Cross-reference: The no-privileged-containers check verifies that containers do not run with securityContext.privileged: true, which would override non-root restrictions.
Detail on fail: Specify what was found. Example: "Dockerfile does not include a USER directive — container runs as root" or "Kubernetes Deployment lacks securityContext.runAsNonRoot configuration"
Remediation: Running as root allows any container escape vulnerability to compromise the host. Create a dedicated unprivileged user in Dockerfile:
RUN useradd -m -u 1001 appuser
USER appuser
In Kubernetes, enforce it at the pod spec level in your Deployment manifest:
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001