Safeguard
Security Guides•

Should ML training containers run as non-root?

Yes, unless a job truly needs root. How to set a non-root user in a Dockerfile, which Kubernetes settings help, and what to do about GPU and cache paths.

Safeguard Security Team
3 min read

Yes, by default. Docker's guidance is that if a service can run without privileges, you should use USER to switch to a non-root user. Training jobs rarely need root, and they often run untrusted code from notebooks and dependencies, so limiting what that code can do is a cheap, effective step.

Why it matters for ML jobs

A training container usually pulls many packages, loads model files, and runs code a researcher just wrote. If any of it turns out to be hostile, root inside the container gives the attacker more room: writing to system paths, installing tools, and reaching more of the mounted volumes. Non-root does not make a container safe by itself, but it removes easy options.

Set the user in the Dockerfile

Docker's build best practices say to create the user and group first and to assign explicit numeric IDs, because automatically assigned IDs can change across rebuilds. They also advise against sudo.

FROM python:3.12-slim
RUN groupadd -g 10001 trainer && useradd -u 10001 -g trainer -m trainer
WORKDIR /home/trainer/app
COPY --chown=trainer:trainer . .
USER trainer

The explicit ID 10001 matters when you mount volumes, since file ownership on the host is numeric.

Tighten the Kubernetes pod

If jobs run on Kubernetes, the security context adds controls. Two are documented in the Kubernetes tasks page:

  • allowPrivilegeEscalation controls whether a process can gain more privileges than its parent, for example through a setuid binary. The page says it defaults to true when not defined, so set it to false.
  • readOnlyRootFilesystem mounts the container's root file system as read only.
securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true

The page also notes that allowPrivilegeEscalation false cannot be combined with a privileged container or one with the CAP_SYS_ADMIN capability. That is a useful test: if your job needs either, ask why.

What breaks, and how to fix it

SymptomLikely causeFix
Permission denied writing a cacheCache path owned by rootPoint the cache at a writable volume or the user's home
Cannot write to model directoryVolume ownershipMatch the numeric user ID on the volume
Read only file system errorLibrary writes to temp pathsMount a small writable temp volume
GPU not visibleRuntime or device setupCheck the toolkit setup, not user privileges

A read only root file system will reveal every place your code writes. Treat that as a free inventory.

A rollout plan

  1. Pick one training image and add the USER line.
  2. Run a short job and fix write paths.
  3. Add the pod security settings in a test namespace.
  4. Make non-root the template default, with a documented exception process.

Pair this with pinning base images by digest.

Safeguard scans container images and dependencies, and policies can gate a build that violates your rules. Try the free scan at gold.safeguard.sh/scan.

Quick check

Does non-root stop all container escapes?

No. It reduces what code can do inside the container. Keep the runtime and kernel updated as well.

Do GPUs require root?

Not as a rule. GPU access depends on the toolkit and device setup, so troubleshoot that rather than granting root.

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.