Skip to content

Docker images run as root in both server and web Dockerfiles (no USER directive) #25

Open

Description

@jsawyerdev

Summary

Neither server/Dockerfile nor web/Dockerfile sets a USER directive, so both final production images run their process as root by default.

Evidence

  • server/Dockerfile:10-17 — final stage is FROM node:22-slim, no USER instruction anywhere in the file; CMD ["node", "dist/index.js"] therefore runs as root.
  • web/Dockerfile:8-14 — same pattern: final stage FROM node:22-slim, no USER instruction; CMD ["node", "server.js"] runs as root.
  • Confirmed via grep -n "USER" server/Dockerfile web/Dockerfile returning no matches.

Why this matters

Running application containers as root is unnecessary privilege that widens the blast radius of any future code-execution vulnerability (in this app, a dependency, or the Node runtime itself) — a compromised process running as root inside the container has more capability to interact with the container's filesystem/environment than one running as an unprivileged user, and any container-escape-class vulnerability becomes more severe.

Attack or failure scenario

If any future vulnerability (in this codebase or a dependency) allows arbitrary file write or command execution inside either container, the attacker's resulting process runs as root, rather than being constrained to a non-privileged account — a defense-in-depth gap rather than a standalone exploitable bug today.

Root cause

Neither Dockerfile creates or switches to a non-root user; the official node:22-slim base image's default user (root) is used unmodified in the final stage of both.

Recommended fix

Add a non-root user in each final stage, e.g.:

RUN groupadd -r app && useradd -r -g app app
USER app

(or use the node user already present in the official Node.js images: USER node), placed after all COPY/RUN steps that need root (installing dependencies, copying build output) and before CMD. Verify the app can still read/write its required paths (e.g., DATA_DIR for the API) as the non-root user.

Acceptance criteria

  • docker inspect (or docker exec ... whoami) on both running containers reports a non-root user.
  • The app continues to function normally (data directory read/write, port binding) under the new user.

Suggested labels

docker, security (neither exists on this repo; recommend bug)

Priority

P2

Severity

Medium — standard container-hardening gap; not directly exploitable on its own, but removes a meaningful layer of defense-in-depth.

Confidence

Confirmed — read both Dockerfiles in full; no USER directive present in either.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions