From 8758cba1097f6a9ce7e34e11b1a0f53b329f4369 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 29 Jan 2025 23:01:46 +0530 Subject: [PATCH] chore: security patches for dependency chain (#4708) --- package.json | 5 +- pnpm-lock.yaml | 94 +++++++++++++++++-------------------- prod.Dockerfile | 121 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 136 insertions(+), 84 deletions(-) diff --git a/package.json b/package.json index b142bd48..6c377c81 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,11 @@ "pug": "3.0.3", "body-parser": "1.20.3", "path-to-regexp@3.2.0": "3.3.0", + "path-to-regexp@0.1.10": "0.1.12", "micromatch@<4.0.8": "4.0.8", - "dset@3.1.3": "3.1.4" + "dset@3.1.3": "3.1.4", + "nanoid@3.3.7": "3.3.8", + "execa@0.10.0": "2.0.0" }, "packageExtensions": { "@hoppscotch/httpsnippet": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 192eb5d6..d162804f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,11 @@ overrides: pug: 3.0.3 body-parser: 1.20.3 path-to-regexp@3.2.0: 3.3.0 + path-to-regexp@0.1.10: 0.1.12 micromatch@<4.0.8: 4.0.8 dset@3.1.3: 3.1.4 + nanoid@3.3.7: 3.3.8 + execa@0.10.0: 2.0.0 packageExtensionsChecksum: da57d58cd55bf5e7924e59ad5f1485b8 @@ -7493,9 +7496,9 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - execa@0.10.0: - resolution: {integrity: sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==} - engines: {node: '>=4'} + execa@2.0.0: + resolution: {integrity: sha512-+ym7S09yUVPHEhYBsdLm53ZjCmCSeAQVtM/iN9dDj9tbvcBnCeBXTXHPWR9HXzht+vslGROteM8bSUdr4YszUg==} + engines: {node: '>=8'} execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} @@ -7794,9 +7797,9 @@ packages: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} - get-stream@3.0.0: - resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} - engines: {node: '>=4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} @@ -8412,10 +8415,6 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} - is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -9429,8 +9428,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -9525,9 +9524,9 @@ packages: engines: {node: '>= 4'} hasBin: true - npm-run-path@2.0.2: - resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} - engines: {node: '>=4'} + npm-run-path@3.1.0: + resolution: {integrity: sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==} + engines: {node: '>=8'} npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} @@ -9654,6 +9653,10 @@ packages: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} + p-finally@2.0.1: + resolution: {integrity: sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==} + engines: {node: '>=8'} + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -9811,10 +9814,6 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -9842,8 +9841,8 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} - path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} @@ -11033,10 +11032,6 @@ packages: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} - strip-eof@1.0.0: - resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} - engines: {node: '>=0.10.0'} - strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -20225,15 +20220,16 @@ snapshots: events@3.3.0: {} - execa@0.10.0: + execa@2.0.0: dependencies: cross-spawn: 7.0.6 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 + get-stream: 5.2.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 3.1.0 + p-finally: 2.0.1 signal-exit: 3.0.7 - strip-eof: 1.0.0 + strip-final-newline: 2.0.0 optional: true execa@5.1.1: @@ -20318,7 +20314,7 @@ snapshots: methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.12 proxy-addr: 2.0.7 qs: 6.11.0 range-parser: 1.2.1 @@ -20354,7 +20350,7 @@ snapshots: methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.12 proxy-addr: 2.0.7 qs: 6.13.0 range-parser: 1.2.1 @@ -20390,7 +20386,7 @@ snapshots: methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.12 proxy-addr: 2.0.7 qs: 6.13.0 range-parser: 1.2.1 @@ -20702,7 +20698,9 @@ snapshots: get-port@5.1.1: optional: true - get-stream@3.0.0: + get-stream@5.2.0: + dependencies: + pump: 3.0.0 optional: true get-stream@6.0.1: {} @@ -21440,9 +21438,6 @@ snapshots: dependencies: call-bind: 1.0.7 - is-stream@1.1.0: - optional: true - is-stream@2.0.1: {} is-stream@3.0.0: {} @@ -23130,7 +23125,7 @@ snapshots: nanoid@3.3.1: {} - nanoid@3.3.7: {} + nanoid@3.3.8: {} napi-build-utils@1.0.2: {} @@ -23209,9 +23204,9 @@ snapshots: shell-quote: 1.8.1 string.prototype.padend: 3.1.6 - npm-run-path@2.0.2: + npm-run-path@3.1.0: dependencies: - path-key: 2.0.1 + path-key: 3.1.1 optional: true npm-run-path@4.0.1: @@ -23346,6 +23341,9 @@ snapshots: p-finally@1.0.0: optional: true + p-finally@2.0.1: + optional: true + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -23509,9 +23507,6 @@ snapshots: path-is-absolute@1.0.1: {} - path-key@2.0.1: - optional: true - path-key@3.1.1: {} path-key@4.0.0: {} @@ -23534,7 +23529,7 @@ snapshots: lru-cache: 11.0.1 minipass: 7.1.2 - path-to-regexp@0.1.10: {} + path-to-regexp@0.1.12: {} path-to-regexp@3.3.0: {} @@ -23874,13 +23869,13 @@ snapshots: postcss@8.4.32: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.1.0 source-map-js: 1.2.1 postcss@8.4.47: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.1.0 source-map-js: 1.2.1 @@ -24387,7 +24382,7 @@ snapshots: run-applescript@3.2.0: dependencies: - execa: 0.10.0 + execa: 2.0.0 optional: true run-applescript@5.0.0: @@ -24865,9 +24860,6 @@ snapshots: strip-comments@2.0.1: {} - strip-eof@1.0.0: - optional: true - strip-final-newline@2.0.0: {} strip-final-newline@3.0.0: {} diff --git a/prod.Dockerfile b/prod.Dockerfile index fdfbdc67..60c6be55 100644 --- a/prod.Dockerfile +++ b/prod.Dockerfile @@ -1,11 +1,44 @@ -FROM node:20-alpine3.19 AS base_builder +# This step is used to build a custom build of Caddy to prevent +# vulnerable packages on the dependency chain +FROM alpine:3.21.2 AS caddy_builder +RUN apk add curl go + +RUN mkdir -p /tmp/caddy-build + +RUN curl -L -o /tmp/caddy-build/src.tar.gz https://github.com/caddyserver/caddy/releases/download/v2.9.1/caddy_2.9.1_src.tar.gz + +# Checksum verification of caddy source +RUN expected="1cfd6127f9ed8dc908d84d7d14579d3ce5114e8671aa8f786745cb3fe60923e0" && \ + actual=$(sha256sum /tmp/caddy-build/src.tar.gz | cut -d' ' -f1) && \ + [ "$actual" = "$expected" ] && \ + echo "✅ Caddy Source Checksum OK" || \ + (echo "❌ Caddy Source Checksum failed!" && exit 1) + +WORKDIR /tmp/caddy-build +RUN tar xvf /tmp/caddy-build/src.tar.gz + +# Patch to resolve CVE-2024-45339 on glog +RUN go get github.com/golang/glog@v1.2.4 +RUN go mod vendor + +WORKDIR /tmp/caddy-build/cmd/caddy +RUN go build + + + +FROM alpine:3.19.6 AS base_builder +RUN apk add nodejs curl + +# Install NPM from source, as Alpine version is old and has dependency vulnerabilities +# TODO: Find a better method which is resistant to supply chain attacks +RUN sh -c "curl -qL https://www.npmjs.com/install.sh | env npm_install=10.9.2 sh" WORKDIR /usr/src/app ENV HOPP_ALLOW_RUNTIME_ENV=true # Required by @hoppscotch/js-sandbox to build `isolated-vm` -RUN apk add python3 make g++ +RUN apk add python3 make g++ zlib-dev brotli-dev c-ares-dev nghttp2-dev openssl-dev icu-dev RUN npm install -g pnpm COPY pnpm-lock.yaml . @@ -14,12 +47,7 @@ RUN pnpm fetch COPY . . RUN pnpm install -f --offline -RUN npm uninstall -g cross-spawn && \ - npm cache clean --force && \ - # Remove any remaining old versions - find /usr/local/lib/node_modules -name "cross-spawn" -type d -exec rm -rf {} + && \ - # Install cross-spawn v7 globally - npm install -g cross-spawn@^7.0.6 --force + FROM base_builder AS backend_builder WORKDIR /usr/src/app/packages/hoppscotch-backend @@ -29,16 +57,17 @@ RUN pnpm --filter=hoppscotch-backend deploy /dist/backend --prod WORKDIR /dist/backend RUN pnpm exec prisma generate -FROM node:20-alpine3.19 AS backend -RUN apk add caddy -RUN npm install -g pnpm +FROM alpine:3.19.6 AS backend +RUN apk add nodejs curl -RUN npm uninstall -g cross-spawn && \ - npm cache clean --force && \ - # Remove any remaining old versions - find /usr/local/lib/node_modules -name "cross-spawn" -type d -exec rm -rf {} + && \ - # Install cross-spawn v7 globally - npm install -g cross-spawn@^7.0.6 --force +# Install NPM from source, as Alpine version is old and has dependency vulnerabilities +# TODO: Find a better method which is resistant to supply chain attacks +RUN sh -c "curl -qL https://www.npmjs.com/install.sh | env npm_install=10.9.2 sh" + +# Install caddy +COPY --from=caddy_builder /tmp/caddy-build/cmd/caddy/caddy /usr/bin/caddy + +RUN npm install -g pnpm COPY --from=base_builder /usr/src/app/packages/hoppscotch-backend/backend.Caddyfile /etc/caddy/backend.Caddyfile COPY --from=backend_builder /dist/backend /dist/backend @@ -56,16 +85,29 @@ CMD ["node", "prod_run.mjs"] EXPOSE 80 EXPOSE 3170 + + FROM base_builder AS fe_builder WORKDIR /usr/src/app/packages/hoppscotch-selfhost-web RUN pnpm run generate -FROM caddy:2-alpine AS app + + + +FROM alpine:3.19.6 AS app +RUN apk add nodejs curl + +# Install NPM from source, as Alpine version is old and has dependency vulnerabilities +# TODO: Find a better method which is resistant to supply chain attacks +RUN sh -c "curl -qL https://www.npmjs.com/install.sh | env npm_install=10.9.2 sh" + +# Install caddy +COPY --from=caddy_builder /tmp/caddy-build/cmd/caddy/caddy /usr/bin/caddy + COPY --from=fe_builder /usr/src/app/packages/hoppscotch-selfhost-web/prod_run.mjs /site/prod_run.mjs COPY --from=fe_builder /usr/src/app/packages/hoppscotch-selfhost-web/selfhost-web.Caddyfile /etc/caddy/selfhost-web.Caddyfile COPY --from=fe_builder /usr/src/app/packages/hoppscotch-selfhost-web/dist/ /site/selfhost-web -RUN apk add nodejs npm RUN npm install -g @import-meta-env/cli @@ -76,13 +118,29 @@ WORKDIR /site CMD ["/bin/sh", "-c", "node /site/prod_run.mjs && caddy run --config /etc/caddy/selfhost-web.Caddyfile --adapter caddyfile"] + + + + FROM base_builder AS sh_admin_builder WORKDIR /usr/src/app/packages/hoppscotch-sh-admin # Generate two builds for `sh-admin`, one based on subpath-access and the regular build RUN pnpm run build --outDir dist-multiport-setup RUN pnpm run build --outDir dist-subpath-access --base /admin/ -FROM caddy:2-alpine AS sh_admin + + + + +FROM alpine:3.19.6 AS sh_admin +RUN apk add nodejs curl + +# Install NPM from source, as Alpine version is old and has dependency vulnerabilities +# TODO: Find a better method which is resistant to supply chain attacks +RUN sh -c "curl -qL https://www.npmjs.com/install.sh | env npm_install=10.9.2 sh" + +# Install caddy +COPY --from=caddy_builder /tmp/caddy-build/cmd/caddy/caddy /usr/bin/caddy COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/prod_run.mjs /site/prod_run.mjs COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/sh-admin-multiport-setup.Caddyfile /etc/caddy/sh-admin-multiport-setup.Caddyfile @@ -90,7 +148,6 @@ COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/sh-admin- COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/dist-multiport-setup /site/sh-admin-multiport-setup COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/dist-subpath-access /site/sh-admin-subpath-access -RUN apk add nodejs npm RUN npm install -g @import-meta-env/cli @@ -101,7 +158,16 @@ WORKDIR /site CMD ["node","/site/prod_run.mjs"] -FROM node:20-alpine3.19 AS aio +FROM alpine:3.19.6 AS aio + +RUN apk add nodejs curl + +# Install NPM from source, as Alpine version is old and has dependency vulnerabilities +# TODO: Find a better method which is resistant to supply chain attacks +RUN sh -c "curl -qL https://www.npmjs.com/install.sh | env npm_install=10.9.2 sh" + +# Caddy install +COPY --from=caddy_builder /tmp/caddy-build/cmd/caddy/caddy /usr/bin/caddy ENV PRODUCTION="true" ENV PORT=8080 @@ -113,18 +179,9 @@ LABEL org.opencontainers.image.source="https://github.com/hoppscotch/hoppscotch" org.opencontainers.image.url="https://docs.hoppscotch.io" \ org.opencontainers.image.licenses="MIT" -# Run this separately to use the cache from backend -RUN apk add caddy - -RUN apk add tini curl +RUN apk add tini RUN npm install -g pnpm -RUN npm uninstall -g cross-spawn && \ - npm cache clean --force && \ - # Remove any remaining old versions - find /usr/local/lib/node_modules -name "cross-spawn" -type d -exec rm -rf {} + && \ - # Install cross-spawn v7 globally - npm install -g cross-spawn@^7.0.6 --force # Copy necessary files # Backend files