Safeguard
Security Guides•

Why is my container still running as root after I added USER?

USER only sets the default for later steps in one build stage. Check stage order, later USER lines, entrypoint scripts and run time overrides to find root.

Safeguard Security Team
4 min read

A container can still run as root after you add USER because USER only sets the default for later instructions in the current build stage. Typical causes are the line sitting in the wrong stage, a later USER switch back to root, a start script that needs root, or an override when the container starts.

Step 1: prove it

Do not guess. Run the built image and print who it is.

docker run myimage id

If the output shows uid zero, work through the causes below. This test also overrides any default command, so for the real behavior also exec into a running container and run the same command.

Step 2: check which stage has USER

The Dockerfile reference says USER sets the default for the rest of the current build stage. In a multi-stage build, a USER line in the build stage does nothing for the final stage. Put it in the stage that ships.

FROM build AS builder
USER 10001
RUN make app
FROM runtime
COPY app /app

In that sketch the final stage never sets a user, so it runs as root. Move the line after the last FROM.

Step 3: look for a switch back

Docker's best practices page advises against switching USER back and forth often. Search the final stage for a later USER root line, often added to install one more package. Do privileged installs first, then drop privileges as the last step before the start command.

Step 4: check start scripts and capabilities

Some entrypoint scripts change ownership, bind low ports or write to system paths, so authors keep them running as root. Rework them: fix ownership at build time with COPY and the chown option, listen on a high port, and write only to directories the app user owns. The best practices page also says to avoid sudo because of unpredictable terminal and signal behavior.

Step 5: check how it is launched

The image sets a default. Whoever runs it can change that default at start time, and orchestrators can enforce or override users too. Review your compose files and deployment manifests for a user setting, and set a policy that rejects pods or containers that run as root.

Step 6: scan for the pattern

A Dockerfile review can catch a missing USER, but only the built image proves the result. Add a CI step that runs the identity command and fails on uid zero, and use your scanner to flag images whose configuration runs as root.

SymptomLikely cause
id shows zeroNo USER in final stage
USER present but root at runtimeRun time override or later USER root
App cannot write filesCopied files owned by root
Cannot bind port 80Use a high port instead

For the full hardening list, read running a container as non-root.

Try it yourself

Click through it at your own pace, or open it full screen.

Quick check

Does a non-root user make the container safe?

It reduces what a compromised process can do, but it is one layer. Combine it with dropped capabilities, read only filesystems and patched images.

Where should USER go in a multi-stage Dockerfile?

In the final stage, as late as possible, after any steps that need root.

Safeguard

Safeguard does SBOM and dependency scanning, and its policies and gates can run in CI so a bad image does not reach production. You can try a free scan before deciding anything.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.