| Property | Value |
|---|---|
| Severity | Warning |
| Category | Security |
| Default | Enabled |
| Auto-fix | Yes (unsafe) |
Description
This rule detects Dockerfiles where the final stage (or itsFROM ancestry
chain) creates a dedicated user via useradd or adduser, but the effective
runtime identity stays root and no privilege-drop entrypoint pattern is
detected. This is a high-signal indicator of an incomplete hardening attempt
or cargo-culted user setup.
On Windows containers, the rule also detects net user /add and
New-LocalUser commands.
The USER instruction sets the default process identity for the container at
runtime. Creating a user without switching to it means the container runs as
root despite the preparation work.
Suppression
The rule is automatically suppressed when:-
The effective
USERin the final stage is non-root. -
A privilege-drop tool is referenced in ENTRYPOINT or CMD (
gosu,su-exec,suexec,setpriv). -
The base image is known to default to non-root: Distroless
:nonroottags, Chainguard/cgr.dev images, or local stage refs whose parent stage sets a non-rootUSER. -
The created user is referenced in an ownership or permissions context:
- Linux:
COPY --chown,ADD --chown, orRUN chown - Windows:
icacls /grant <user>,icacls /setowner <user>,New-Object ...AccessRule("<user>", ...)
- Linux:
Cross-stage inheritance
The rule walks theFROM <stage> ancestry chain. If a parent stage creates a
user that flows into the final image (via FROM), the rule detects it. User
creation in stages referenced only by COPY --from does not trigger the rule,
since COPY does not inherit /etc/passwd.
Relationship to other rules
hadolint/DL3002 | tally/stateful-root-runtime | tally/user-created-but-never-used | |
|---|---|---|---|
| Fires when | Last USER is explicitly root | Root + stateful signal (VOLUME, data dirs) | User created but never switched to |
| Scope | Explicit root USER only | Root + state combination | User creation without USER switch |
| Privilege-drop aware | No | Yes | Yes |
| Ownership suppression | N/A | N/A | Yes (—chown, chown, icacls) |
Auto-fix
The rule offers an unsafe auto-fix (requires--fix-unsafe) that inserts
USER <created_user> before the first ENTRYPOINT or CMD in the final
stage. The fix is marked unsafe because:
- Subsequent instructions might require root.
- A privilege-drop pattern (gosu) might be more appropriate.
- The inserted
USERmight not be the correct resolution in all cases.
References
- Dockerfile reference — USER
- Dockerfile reference — COPY —chown
- Docker Blog — Understanding the Docker USER Instruction
- Chainguard Best Practices