Safeguard
Developer Tools•

Which UID should a container user have, and how do you chown files?

Image users get unpredictable IDs unless you set them. Use an explicit numeric UID and COPY with chown so a non-root container can read what it needs.

Safeguard Security Team
3 min read

Give the container user an explicit numeric UID and GID, switch to it with USER, and set ownership of copied files with COPY and the chown option using the same numbers. Docker warns that user IDs created in an image are not deterministic, so a fixed number keeps permissions predictable.

Why the number matters

Docker's best practices page says users and groups in an image are assigned a non-deterministic UID and GID, and suggests an explicit one if it matters. It matters more often than people think. Volume mounts, read only filesystems and Kubernetes settings that require a non-root numeric user all compare numbers, not names.

RUN groupadd -g 10001 app && useradd -u 10001 -g 10001 -r app
USER 10001:10001

Pick a high number that will not collide with host users. Using the same number across your services makes shared volume permissions simpler.

What COPY does to ownership

The Dockerfile reference says that without the chown option, copied files get UID and GID zero, which means root. A non-root process may then be unable to write where it needs to, or you end up tempted to loosen permissions. Set ownership at copy time instead.

# COPY with the chown option set to 10001:10001
COPY ./app /app

The reference adds two details. Names are resolved through the passwd and group files inside the image, so the build fails if the name is missing there. Numeric IDs skip that lookup, and a numeric UID given without a group also uses the same number as the GID. When you combine copy with the link option, you must use numeric IDs.

What USER covers

USER sets the default user for the rest of the build stage. It applies to RUN instructions and to the runtime ENTRYPOINT and CMD. Two traps from the reference: if you name a group, the user gets only that group, and a user with no primary group runs with the root group. State both values to avoid surprises.

Make the app writable only where needed

Most web services need to write to a temp directory and maybe a cache. Create those paths in the build, give them to the app user, and keep the rest of the tree owned by root and read only for the app. A compromised process then cannot edit its own code.

PathOwnerApp user can write
Application coderootNo
Temp and cache directoriesapp userYes
Mounted data volumematches UIDYes, if intended

Checking your work

Run the image and print the identity with the id command, then try to write to a code directory and confirm it fails. For the wider checklist, see running a container as non-root.

Quick check

Is a username in USER enough?

It works, but the numeric ID is less ambiguous. Some policies check numbers, and a name needs a matching entry in the image's passwd file.

Why are my copied files owned by root?

COPY gives files UID and GID zero unless you use the chown option.

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.