From adecb18f4244373ccbf433c5892e388a43febfc1 Mon Sep 17 00:00:00 2001 From: JOY Date: Thu, 17 Sep 2026 00:07:55 +0700 Subject: [PATCH] fix(docker): run the web image as the non-root node user and ignore secrets The runner stage operated as root (audit HI-12 remainder): a container escape would land directly on root. Copy the app tree with --chown so the unprivileged node user owns it (keeping runtime cache writes working) and switch to USER node after the root-only apt step. .dockerignore now excludes .env*, *.pem, *.key, *.p12, *.pfx and .husky so local secrets cannot be baked into image layers. The root context is shared by the api/v2 image build, which protects that image too. --- .dockerignore | 10 ++++++++++ Dockerfile | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index 236b80b4b11..c2edf96a877 100644 --- a/.dockerignore +++ b/.dockerignore @@ -34,3 +34,13 @@ Thumbs.db # Examples and docs docs + +# Secrets and local env - must never land in an image layer (audit HI-12). +# Applies to every build using the repo root as context (web + api/v2). +.env +.env.* +*.pem +*.key +*.p12 +*.pfx +.husky diff --git a/Dockerfile b/Dockerfile index 854f1fdea0e..672a3ae9960 100644 --- a/Dockerfile +++ b/Dockerfile @@ -101,7 +101,10 @@ WORKDIR /calcom RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd wget && rm -rf /var/lib/apt/lists/* -COPY --from=builder-two /calcom ./ +# Why --chown: the container runs as the non-root node user (USER below); owning +# the tree lets the runtime write its caches (Next ISR, prisma engines) without +# adding a duplicate copy-up layer that a separate chown -R would create. +COPY --from=builder-two --chown=node:node /calcom ./ ARG NEXT_PUBLIC_WEBAPP_URL=https://cal.crove.com ENV NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL \ BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL @@ -109,6 +112,10 @@ ENV NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL \ ENV NODE_ENV=production EXPOSE 3000 +# HI-12: run as the unprivileged node user (uid 1000) shipped with the base +# image instead of root; apt above already ran as root. +USER node + HEALTHCHECK --interval=30s --timeout=30s --retries=5 \ CMD wget --spider http://localhost:3000 || exit 1