Skip to content

chore(docker): clear most CVEs in published image (npm/pnpm/uuid + drop curl)#7674

Open
JohnMcLear wants to merge 3 commits intodevelopfrom
chore/docker-cve-sweep
Open

chore(docker): clear most CVEs in published image (npm/pnpm/uuid + drop curl)#7674
JohnMcLear wants to merge 3 commits intodevelopfrom
chore/docker-cve-sweep

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

@JohnMcLear JohnMcLear commented May 5, 2026

Summary

Cuts published-image vulnerabilities reported by docker scout from 18 (0C/4H/13M/1L) across 8 packages → 12 (0C/2H/9M/1L) across 3 packages, locally verified against etherpad/etherpad:2.7.2.

The three remaining flagged packages — curl/libcurl, git, busybox — are all upstream Alpine 3.23 packages currently marked not fixed. libcurl is a transitive dep of git and can't be removed independently; the curl advisories scout still attributes to it are SMB-protocol use-after-frees that are unreachable from any code we ship.

Changes

  • Provision pnpm via corepack and remove bundled npm. The node:22-alpine base ships npm@10.9.7 whose bundled transitives carry CVEs we don't need at runtime: picomatch 4.0.3 (CVE-2026-33671 high, CVE-2026-33672) and brace-expansion 2.0.2 (CVE-2026-33750). Corepack provisions pnpm directly and we delete /usr/local/lib/node_modules/npm plus its CLI shims. Clears 1 high + 1 medium.
  • Bump PnpmVersion 10.28.2 → 10.33.2. Aligns with the workflow's pnpm/action-setup pinning and brings pnpm's bundled brace-expansion to 5.0.5 (was 5.0.4 / CVE-2026-33750). Clears 1 medium.
  • Add uuid@<14.0.0>=14.0.0 override. Fixes GHSA-w5hq-g745-h8pq. Lockfile resolves to uuid@14.0.0. Clears 1 medium.
  • Drop curl from runtime apk add and switch HEALTHCHECK to wget. curl was only invoked by the HEALTHCHECK and a couple of dev/CI scripts that don't run in the container. wget (busybox built-in) replaces it. Side-effect: clears nghttp2 (CVE-2026-27135 high), which was a curl-CLI runtime dep.
  • HEALTHCHECK URL localhost127.0.0.1. Alpine/musl resolves localhost to ::1 first and Etherpad only binds IPv4 — was producing `Connection refused` until the IPv4 fallback timed out.

Test plan

  • `docker build --target production` passes
  • container starts and reports `healthy`
  • `docker scout cves` confirms reduction (18 → 12 CVEs, 8 → 3 packages)
  • CI: docker.yml `build-test`, `build-test-db-drivers`, and full test suites green

🤖 Generated with Claude Code

…rop curl

Cuts published-image vulnerabilities from 18 (4H/13M/1L) across 8 packages
to 12 (2H/9M/1L) across 3 packages. The remaining three (curl/libcurl,
git, busybox) are all upstream Alpine 3.23 packages with "not fixed"
status — libcurl is pulled in transitively by git and cannot be
removed independently.

Changes:

- Provision pnpm via corepack instead of `npm install -g pnpm`, then
  remove the bundled npm. The base image's npm@10.9.7 ships old
  transitives (picomatch 4.0.3 → CVE-2026-33671/33672, brace-expansion
  2.0.2 → CVE-2026-33750) that we don't otherwise need at runtime;
  corepack handles pnpm directly without npm. Fixes 1H + 1M.

- Bump PnpmVersion 10.28.2 → 10.33.2 to align with the rest of the
  workflow and pull in pnpm's patched bundled brace-expansion (5.0.5
  vs 5.0.4). Fixes 1M.

- Add `uuid@<14.0.0` → `>=14.0.0` to pnpm.overrides
  (GHSA-w5hq-g745-h8pq). Fixes 1M.

- Drop `curl` from the runtime apk add list and switch HEALTHCHECK to
  wget (busybox built-in). curl was only invoked by the healthcheck and
  by dev/CI scripts that don't run in the container. Removes the curl
  CLI binary; libcurl remains as a git transitive dep, so the
  `apk/alpine/curl` advisories scout reports against libcurl persist
  but aren't reachable from any code we ship. As a side-effect this
  also clears nghttp2 (CVE-2026-27135) which was a curl-CLI dep.

- Switch HEALTHCHECK URL from `localhost` to `127.0.0.1` — alpine/musl
  resolves localhost to ::1 first and Etherpad only binds IPv4.

Verified locally: docker build → docker run → healthy → docker scout
cves shows 12 CVEs / 3 packages.
@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 5, 2026

Review Summary by Qodo

(Agentic_describe updated until commit 5a8561f)

Reduce published Docker image CVEs via pnpm/corepack and curl removal

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Reduce Docker image CVEs from 18 to 12 by removing npm and curl
• Provision pnpm via corepack instead of npm to eliminate bundled vulnerabilities
• Bump pnpm version 10.28.2 → 10.33.2 and add uuid override
• Fix HEALTHCHECK by switching from curl to wget and localhost to 127.0.0.1
Diagram
flowchart LR
  A["Node 22 Alpine<br/>npm@10.9.7"] -->|"Remove bundled npm"| B["Corepack<br/>pnpm@10.33.2"]
  C["npm transitives<br/>picomatch/brace-expansion<br/>CVE-2026-33671/33672/33750"] -->|"Eliminated"| D["4 CVEs cleared"]
  E["curl runtime dep<br/>nghttp2 CVE-2026-27135"] -->|"Replace with wget"| F["1 CVE cleared"]
  G["uuid@8.3.2<br/>GHSA-w5hq-g745-h8pq"] -->|"Override to 14.0.0"| H["1 CVE cleared"]
  I["HEALTHCHECK localhost<br/>IPv6 resolution issue"] -->|"Switch to 127.0.0.1"| J["Connection refused fixed"]
  D --> K["18 CVEs → 12 CVEs<br/>8 packages → 3 packages"]
  F --> K
  H --> K
Loading

Grey Divider

File Changes

1. Dockerfile Bug fix, security hardening +13/-5

Provision pnpm via corepack, drop curl, fix HEALTHCHECK

• Bump PnpmVersion from 10.28.2 to 10.33.2
• Replace npm install -g pnpm with corepack provisioning and remove bundled npm binaries
• Remove curl from runtime apk packages
• Switch HEALTHCHECK from curl to wget and localhost to 127.0.0.1
• Add corepack refresh workaround for stale signing-key list in Node 22

Dockerfile


2. package.json Security hardening +1/-0

Add uuid version override for CVE fix

• Add uuid@<14.0.0>=14.0.0 override to pnpm.overrides
• Fixes GHSA-w5hq-g745-h8pq vulnerability in uuid package

package.json


3. pnpm-lock.yaml Dependencies, configuration changes +49/-13

Lock file updates for uuid and binding packages

• Add uuid@<14.0.0: '>=14.0.0' override entry
• Update uuid resolution from 8.3.2 to 14.0.0
• Add libc field specifications to multiple native binding packages (@oxc-minify, @rolldown,
 @unrs/rspack-resolver, lightningcss, rusty-store-kv)
• Update @azure/msal-node uuid dependency from 8.3.2 to 14.0.0
• Simplify eslint-plugin-import peer dependency resolution

pnpm-lock.yaml


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 5, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2)

Grey Divider


Action required

1. Corepack pnpm prepare failure ✓ Resolved 🐞 Bug ☼ Reliability
Description
The Dockerfile now runs corepack prepare pnpm@${PnpmVersion} --activate without first updating
corepack; this repo already documents that Node 22’s bundled corepack can reject newer pnpm versions
due to a stale signing-key list, which would fail the Docker build at that step. This occurs in both
the adminbuild and build stages, so a rejection would block image builds entirely.
Code

Dockerfile[R13-16]

+# Use corepack to provision pnpm and drop the bundled npm — its older
+# transitives (picomatch, brace-expansion) carry CVEs we don't otherwise need.
+RUN corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
+    rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
Evidence
Dockerfile uses corepack to prepare pnpm (and removes npm afterwards), while snap packaging
explicitly upgrades corepack first because the Node 22-bundled corepack may reject newer pnpm
releases; the same corepack rejection would fail the Docker build at corepack prepare.

Dockerfile[12-20]
Dockerfile[98-109]
snap/snapcraft.yaml[111-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Dockerfile provisions pnpm via `corepack prepare pnpm@${PnpmVersion} --activate` but does not refresh corepack first. The repo’s snap build already documents that Node 22’s bundled corepack can reject newer pnpm versions due to stale signing keys; if that happens here, the image build fails at `corepack prepare`.
### Issue Context
- This is done in *two* stages (`adminbuild` and `build`).
- The snap packaging flow addresses the exact failure mode by upgrading corepack before running `corepack prepare`.
### Fix Focus Areas
- Dockerfile[12-20]
- Dockerfile[98-109]
- snap/snapcraft.yaml[111-118]
### Implementation direction
- In both Dockerfile stages, install/upgrade corepack (using the bundled npm *before* deleting npm), then run `corepack enable` + `corepack prepare pnpm@${PnpmVersion} --activate`, then remove npm/npx as you do today.
- Keep/extend the comment to explain why corepack is upgraded first (mirror the rationale in `snap/snapcraft.yaml`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unpinned corepack version 🐞 Bug ⛨ Security ⭐ New
Description
The Dockerfile installs corepack via npm install -g corepack@latest, so rebuilding the same
Dockerfile at different times can pull different corepack versions and change behavior or break
builds. This reduces reproducibility and increases supply-chain risk for the published image build
pipeline.
Code

Dockerfile[R18-20]

+RUN npm install -g corepack@latest && \
+    corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
+    rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
Evidence
Both the admin build stage and the main build stage install Corepack from the floating latest tag,
so the resulting image contents depend on build time rather than the repo state.

Dockerfile[12-20]
Dockerfile[102-114]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The Dockerfile installs `corepack` from `corepack@latest`, which is non-deterministic across rebuilds.

### Issue Context
`latest` will resolve to different versions over time, so the same git SHA can produce different images.

### Fix Focus Areas
- Dockerfile[12-20]
- Dockerfile[102-114]

### Suggested fix
- Introduce an explicit version (e.g. `ARG CorepackVersion=...`) and use `npm install -g corepack@${CorepackVersion}` in both stages.
- Consider pinning to the same version you validated locally/CI (and keep the pnpm version pin you already have).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Forced uuid major upgrade 🐞 Bug ☼ Reliability ⭐ New
Description
The new pnpm override forces uuid from <14 to >=14 across the workspace, changing the resolved
uuid version used by @azure/msal-node. Because this bypasses downstream semver constraints, it
can break any runtime path that loads @azure/msal-node if it is incompatible with uuid@14.
Code

package.json[77]

+      "uuid@<14.0.0": ">=14.0.0",
Evidence
The repo-wide override explicitly forces uuid to 14+, and the lockfile shows
@azure/msal-node@5.1.4 now depends on uuid: 14.0.0, so any incompatibility will surface when
msal-node is loaded.

package.json[54-80]
pnpm-lock.yaml[18-26]
pnpm-lock.yaml[6033-6044]
pnpm-lock.yaml[5559-5562]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The pnpm override forces a major `uuid` upgrade broadly (`>=14.0.0`), which can unintentionally pull newer `uuid` versions later and may violate transitive dependencies’ expectations.

### Issue Context
Lockfile currently resolves `uuid@14.0.0` for `@azure/msal-node`, but the override allows future automatic upgrades beyond 14.0.0 without review.

### Fix Focus Areas
- package.json[54-80]
- pnpm-lock.yaml[18-26]

### Suggested fix
- Change the override value from `>=14.0.0` to an exact pin (e.g. `14.0.0`) or a tightly-scoped range you’re comfortable supporting.
- Add/extend CI coverage to exercise/import the relevant Azure/MSAL path if it is a supported runtime feature.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. curl removed from image 📘 Rule violation ⚙ Maintainability
Description
The PR removes the curl package from the runtime image, which can break existing user workflows or
automation that execs into the container and relies on curl being present. This is a
backwards-incompatible change to the published container environment without an in-repo
compatibility/mitigation mechanism.
Code

Dockerfile[103]

-        curl \
Evidence
PR Compliance ID 2 requires avoiding backwards-incompatible changes without mitigation; the
Dockerfile explicitly removes curl from the installed runtime packages.

Dockerfile[103-103]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The runtime Docker image no longer installs `curl`, which can be a backwards-incompatible change for users who rely on `curl` being available inside the container.
## Issue Context
This PR intentionally drops `curl` to reduce CVEs, but the published image environment is part of the user-facing surface area; removing commonly-used tooling can break downstream scripts.
## Fix Focus Areas
- Dockerfile[99-109]
(Consider a mitigation such as an opt-in build arg to include `curl`, a separate image/tag variant, and/or documenting the removal prominently in existing Docker image documentation/release notes.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. npm/npx removed from image 📘 Rule violation ⚙ Maintainability
Description
The PR deletes the npm and npx binaries and the bundled npm installation from the image, which
can break existing workflows that expect npm tooling to exist in the published container. This is
a backwards-incompatible change to the container environment without an in-repo
compatibility/mitigation mechanism.
Code

Dockerfile[103]

+    rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx && \
Evidence
PR Compliance ID 2 requires avoiding backwards-incompatible changes without mitigation; the
Dockerfile explicitly removes /usr/local/lib/node_modules/npm and the npm/npx shims from the
image.

Dockerfile[102-103]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Docker image no longer includes `npm`/`npx` due to explicit deletion of the bundled npm installation and shims, which can be backwards-incompatible for users.
## Issue Context
This PR removes npm to reduce CVEs and standardize on pnpm via corepack, but users may have scripts that run `npm` inside the container (for debugging, plugin installation, etc.).
## Fix Focus Areas
- Dockerfile[10-16]
- Dockerfile[99-109]
(Consider a mitigation such as providing an opt-in build arg or separate image/tag that retains `npm`/`npx`, and/or documenting the removal prominently in the Docker image docs/release notes.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit 5a8561f

Results up to commit 417b65d


🐞 Bugs (1) 📘 Rule violations (2)


Action required
1. Corepack pnpm prepare failure 🐞 Bug ☼ Reliability
Description
The Dockerfile now runs corepack prepare pnpm@${PnpmVersion} --activate without first updating
corepack; this repo already documents that Node 22’s bundled corepack can reject newer pnpm versions
due to a stale signing-key list, which would fail the Docker build at that step. This occurs in both
the adminbuild and build stages, so a rejection would block image builds entirely.
Code

Dockerfile[R13-16]

+# Use corepack to provision pnpm and drop the bundled npm — its older
+# transitives (picomatch, brace-expansion) carry CVEs we don't otherwise need.
+RUN corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
+    rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
Evidence
Dockerfile uses corepack to prepare pnpm (and removes npm afterwards), while snap packaging
explicitly upgrades corepack first because the Node 22-bundled corepack may reject newer pnpm
releases; the same corepack rejection would fail the Docker build at corepack prepare.

Dockerfile[12-20]
Dockerfile[98-109]
snap/snapcraft.yaml[111-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The Dockerfile provisions pnpm via `corepack prepare pnpm@${PnpmVersion} --activate` but does not refresh corepack first. The repo’s snap build already documents that Node 22’s bundled corepack can reject newer pnpm versions due to stale signing keys; if that happens here, the image build fails at `corepack prepare`.

### Issue Context
- This is done in *two* stages (`adminbuild` and `build`).
- The snap packaging flow addresses the exact failure mode by upgrading corepack before running `corepack prepare`.

### Fix Focus Areas
- Dockerfile[12-20]
- Dockerfile[98-109]
- snap/snapcraft.yaml[111-118]

### Implementation direction
- In both Dockerfile stages, install/upgrade corepack (using the bundled npm *before* deleting npm), then run `corepack enable` + `corepack prepare pnpm@${PnpmVersion} --activate`, then remove npm/npx as you do today.
- Keep/extend the comment to explain why corepack is upgraded first (mirror the rationale in `snap/snapcraft.yaml`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
2. curl removed from image 📘 Rule violation ⚙ Maintainability
Description
The PR removes the curl package from the runtime image, which can break existing user workflows or
automation that execs into the container and relies on curl being present. This is a
backwards-incompatible change to the published container environment without an in-repo
compatibility/mitigation mechanism.
Code

Dockerfile[103]

-        curl \
Evidence
PR Compliance ID 2 requires avoiding backwards-incompatible changes without mitigation; the
Dockerfile explicitly removes curl from the installed runtime packages.

Dockerfile[103-103]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The runtime Docker image no longer installs `curl`, which can be a backwards-incompatible change for users who rely on `curl` being available inside the container.

## Issue Context
This PR intentionally drops `curl` to reduce CVEs, but the published image environment is part of the user-facing surface area; removing commonly-used tooling can break downstream scripts.

## Fix Focus Areas
- Dockerfile[99-109]

(Consider a mitigation such as an opt-in build arg to include `curl`, a separate image/tag variant, and/or documenting the removal prominently in existing Docker image documentation/release notes.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. npm/npx removed from image 📘 Rule violation ⚙ Maintainability
Description
The PR deletes the npm and npx binaries and the bundled npm installation from the image, which
can break existing workflows that expect npm tooling to exist in the published container. This is
a backwards-incompatible change to the container environment without an in-repo
compatibility/mitigation mechanism.
Code

Dockerfile[103]

+    rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx && \
Evidence
PR Compliance ID 2 requires avoiding backwards-incompatible changes without mitigation; the
Dockerfile explicitly removes /usr/local/lib/node_modules/npm and the npm/npx shims from the
image.

Dockerfile[102-103]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Docker image no longer includes `npm`/`npx` due to explicit deletion of the bundled npm installation and shims, which can be backwards-incompatible for users.

## Issue Context
This PR removes npm to reduce CVEs and standardize on pnpm via corepack, but users may have scripts that run `npm` inside the container (for debugging, plugin installation, etc.).

## Fix Focus Areas
- Dockerfile[10-16]
- Dockerfile[99-109]

(Consider a mitigation such as providing an opt-in build arg or separate image/tag that retains `npm`/`npx`, and/or documenting the removal prominently in the Docker image docs/release notes.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

@JohnMcLear JohnMcLear marked this pull request as draft May 5, 2026 14:59
Comment thread Dockerfile
Node 22's bundled corepack ships a stale signing-key list and can reject
newer pnpm releases (nodejs/corepack#612), which would fail the image
build at `corepack prepare`. Mirror the snap/snapcraft.yaml workaround:
`npm install -g corepack@latest` before activating pnpm, in both
adminbuild and build stages. npm is still removed afterwards.
@JohnMcLear
Copy link
Copy Markdown
Member Author

Qodo review responses:

1. Corepack pnpm prepare failure (Bug): fixed in 5a8561fnpm install -g corepack@latest now runs in both stages before corepack prepare, mirroring the snap/snapcraft.yaml workaround for nodejs/corepack#612.

2. curl removed from image (Rule violation): intentional. The runtime curl CLI was unused except by the HEALTHCHECK (now wget — busybox built-in, always present). Dropping it eliminates 10 CVEs (1H/8M/1L) plus its nghttp2 dep. Operators who exec into the container for ad-hoc HTTP can still use wget; if they specifically need curl they can apk add curl post-up. Will note in the next release's docker section.

3. npm/npx removed from image (Rule violation): intentional. Etherpad uses pnpm exclusively at runtime (bin/installDeps.sh, pnpm run prod, plugin install via pnpm run plugins i); npm in the published container was dead weight that carried CVEs in its bundled transitives (picomatch 4.0.3, brace-expansion 2.0.2). pnpm is provisioned via corepack, so the package-manager surface is preserved — just on the modern tool. Same release-note disclosure path.

@JohnMcLear JohnMcLear marked this pull request as ready for review May 5, 2026 15:47
@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 5, 2026

Persistent review updated to latest commit 5a8561f

Address Qodo's "backwards-incompatible change without mitigation" rule
violations by documenting the removal in the 2.7.3 breaking-changes
section. Operators who exec into the container can apk add curl on
demand or use the busybox wget / pnpm already present.
@JohnMcLear
Copy link
Copy Markdown
Member Author

Re-checking the rule-violation findings after pushing 5a8561f — Qodo's reply was paused at the free-tier limit, but I went back through them and added the missing mitigation:

#2 (curl) and #3 (npm/npx): documented in CHANGELOG.md 2.7.3 breaking changes (commit f42ffef). Operators who exec into the container and need either tool can apk add curl or fall back to the already-present busybox wget / pnpm. That closes the "backwards-incompatible change without mitigation" gap that PR Compliance ID 2 is asking for.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant