[GH-ISSUE #4677] [bug]: Container images should not run as root user #1739

Open
opened 2026-03-16 21:34:34 +03:00 by kerem · 1 comment
Owner

Originally created by @muellerst-hg on GitHub (Jan 16, 2025).
Original GitHub issue: https://github.com/hoppscotch/hoppscotch/issues/4677

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

By default, both the HoppScotch AIO image as well as the three individual container images run their processes as root user.

Threat model

The threat models of root containers are that attackers can misuse privileges to:

  • break out to the host node
  • break the isolation between containers.

Reason

The underlying base images caddy:2-alpine and node:20-alpine3.19 by default use root user and the HoppScotch Dockerfile never sets the USER.

Solution

Instead, the container processes should be run by an unprivileged user, which is a containerization best practice.
This can be achieved in the Dockerfile by using creating a non-privileged user or use an existing one from the base image (e.g. node with uid 1000) and handing over with USER

Workarounds

Forcing the container orchestration to run the container as different user (e.g. using securtyContext) fails, because the process at least on startup needs write access to directories owned by root, e.g. /site/build.env. So switching to a non-privileged user would also require to change directory/file permissions.

Steps to reproduce

Check which user is used in the AIO container image

$ docker run -p 3000:3000 -p 3100:3100 -p 3170:3170 --env-file .env hoppscotch/hoppscotch id

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

Try to start the AIO container image as non-privileged user node

$ docker run -p 3000:3000 -p 3100:3100 -p 3170:3170 --env-file .env --user node hoppscotch/hoppscotch

node:fs:2367
    return binding.writeFileUtf8(
                   ^

Error: EACCES: permission denied, open 'build.env'
    at Object.writeFileSync (node:fs:2367:20)
    at file:///usr/src/app/aio_run.mjs:46:4
    at ModuleJob.run (node:internal/modules/esm/module_job:234:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:473:24)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:122:5) {
  errno: -13,
  code: 'EACCES',
  syscall: 'open',
  path: 'build.env'
}

Node.js v20.18.1

Alternatively, in Kubernetes try running the pods with the following securityContext with the same output as above:

securityContext:
  runAsUser: 1000

Environment

Production

Version

Self-hosted

Originally created by @muellerst-hg on GitHub (Jan 16, 2025). Original GitHub issue: https://github.com/hoppscotch/hoppscotch/issues/4677 ### Is there an existing issue for this? - [X] I have searched the existing issues ### Current behavior By default, both the HoppScotch AIO image as well as the three individual container images run their processes as root user. ### Threat model The threat models of root containers are that attackers can misuse privileges to: - break out to the host node - break the isolation between containers. ### Reason The underlying base images `caddy:2-alpine` and `node:20-alpine3.19` by default use root user and the HoppScotch Dockerfile never sets the `USER`. ### Solution Instead, the container processes should be run by an unprivileged user, which is a containerization best practice. This can be achieved in the Dockerfile by using creating a non-privileged user or use an existing one from the base image (e.g. `node` with uid 1000) and handing over with `USER` ### Workarounds Forcing the container orchestration to run the container as different user (e.g. using securtyContext) fails, because the process at least on startup needs write access to directories owned by root, e.g. `/site/build.env`. So switching to a non-privileged user would also require to change directory/file permissions. ### Steps to reproduce Check which user is used in the AIO container image ``` $ docker run -p 3000:3000 -p 3100:3100 -p 3170:3170 --env-file .env hoppscotch/hoppscotch id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) ``` Try to start the AIO container image as non-privileged user `node` ``` $ docker run -p 3000:3000 -p 3100:3100 -p 3170:3170 --env-file .env --user node hoppscotch/hoppscotch node:fs:2367 return binding.writeFileUtf8( ^ Error: EACCES: permission denied, open 'build.env' at Object.writeFileSync (node:fs:2367:20) at file:///usr/src/app/aio_run.mjs:46:4 at ModuleJob.run (node:internal/modules/esm/module_job:234:25) at async ModuleLoader.import (node:internal/modules/esm/loader:473:24) at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:122:5) { errno: -13, code: 'EACCES', syscall: 'open', path: 'build.env' } Node.js v20.18.1 ``` Alternatively, in Kubernetes try running the pods with the following securityContext with the same output as above: ``` securityContext: runAsUser: 1000 ``` ### Environment Production ### Version Self-hosted
Author
Owner

@rb090 commented on GitHub (Jan 22, 2026):

Thank you @muellerst-hg for creating this issue 🙌.

I would also like to the container processes to run by an unprivileged user. I strongly agree with this best practice. Can you please share if there is any updates on this @AndrewBastin @liyasthomas? I am using the AIO container atm.

<!-- gh-comment-id:3785519515 --> @rb090 commented on GitHub (Jan 22, 2026): Thank you @muellerst-hg for creating this issue 🙌. I would also like to the container processes to run by an unprivileged user. I strongly agree with this best practice. Can you please share if there is any updates on this @AndrewBastin @liyasthomas? I am using the AIO container atm.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hoppscotch#1739
No description provided.