Repository navigation
chore(docker): bump the Node base image to clear container vulnerabilities - #663
Merged
Merged
Conversation
The Inspector scan of `pr-662-latest` reported 87 findings: 5 critical, 44 high, 29 medium, 9 low. Every one traces to the base image. None come from `/app`, so neither the application nor its pnpm dependencies contribute. Three changes, measured against that scan: - Move the base from `node:24.14.0-alpine3.22` to `node:24.21.0-alpine3.23`. Alpine 3.22 is the constraint: upstream stopped publishing Node on it in May 2026, so it caps Node at 24.16.0, which leaves the one critical Node CVE genuinely unfixed. Alpine 3.23 keeps `musl` on 1.2.5, the same minor as 3.22, so the prebuilt `sharp` binaries see no ABI change. Only 3.24 moves to 1.2.6. - Add `apk upgrade` to `base`. The image ships OpenSSL 3.5.7-r0 and the branch serves 3.5.8-r0, which 10 findings ask for, 2 of them critical. - Delete the bundled `npm` tree, `corepack`, and `include/node` in `runtime`. Nothing calls them, and they account for 53 of the 87 findings. This clears 59 of 87. The 28 that remain all sit on the Node binary and all carry a `fixedInVersion` naming Node 25 or 26. Checked against NVD per release line, they are scanner artefacts: the three cohorts were fixed in Node 24 at 24.14.1, 24.17.0, and 24.19.0, all at or below 24.21.0. The baseline data shows the same effect, because it reports CVE-2026-21637 against 24.14.0 while NVD records that one as fixed in 24.13.0. Verified: all 6 stages build; `node --version` is v24.21.0; OpenSSL reaches 3.5.8-r0; all 6 removed paths are gone and no `opensslv.h` remains; `sharp` 0.35.4 on libvips 8.18.6 encodes AVIF on musl; the migrate image loads Prisma 7.10.0 and reaches the database step; `pnpm test run` passes 651 tests; `pnpm check` reports 0 errors and 0 warnings; `pnpm lint` is clean. Refs #656 Co-Authored-By: Claude Opus 5 <[email protected]>
docker): bump the Node base image and strip unused Node partsdocker): bump the Node base image to clear container vulnerabilities
nicholasjjlim
marked this pull request as ready for review
September 17, 2026 06:35
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #656
🚀 Summary
node:24.21.0-alpine3.23, applies the outstanding Alpine security updates, and deletes the Node parts that no published stage runs.pr-662-latest(5 critical, 44 high, 29 medium, 9 low) come from the base image. Not one sits under/app, so neither the app nor its pnpm tree contributes.✏️ Changes
Dockerfile, three edits:Dockerfile:4):24.14.0-alpine3.22to24.21.0-alpine3.23. Alpine 3.22 caps Node at 24.16.0, which NVD still lists as affected by the one critical Node CVE. Alpine 3.23 holdsmuslat 1.2.5, the same minor as 3.22, so the prebuiltsharpbinaries see no ABI change. Only 3.24 moves musl to 1.2.6.apk upgrade --no-cacheinbase: the image shipslibssl3andlibcrypto3at3.5.7-r0, and thev3.23branch already serves the3.5.8-r0that 10 findings ask for, 2 of them critical. It runs before the existingwget, so that download uses the current OpenSSL. It trades exact reproducibility for those backports.runtime: the bundlednpmandcorepacktrees,/usr/local/include/node, and theirbinsymlinks. Nothing callsnpm:pnpmis a checksum-verified static binary, and both published stages start throughnode. Theinclude/nodedirectory holds Node's vendored OpenSSL headers, which 32 findings match. This stays out ofbase, becausebuildalso derives frombaseand needs the full toolchain.🧪 Test plan
No automated test covers a
Dockerfile, so each done-when item below was checked by hand against the built images.Dockerfile:4:24.21.0-alpine3.23. This deviates from the tag the issue names. Node is newer and Alpine is one release lower, to hold musl at 1.2.5.docker buildsucceeds for every stage: all 6 build (base,build,prod-deps,runtime,migrate,production).node --versionin the image:v24.21.0.pnpm test run,pnpm check,pnpm lint: 651 tests pass; 5692 files with 0 errors and 0 warnings; lint clean.prisma.config.tsand the schema, then failsP1001against a dead host.sharpstill works:sharp 0.35.4onlibvips 8.18.6encoded and re-read an AVIF image on musl 1.2.5.pnpm buildalso produced 204 image files.✅ Manual verification
Scan
pr-663-latestin ECR after this merges. Query thelinux/arm64child manifest rather than the tag, because the tag is an OCI index and returnsUNSUPPORTED_IMAGE. Expect 28 findings: 1 critical, 8 high, 13 medium, 6 low.Read those 28 as artefacts before you treat them as work. Each sits on the Node binary, and each carries a
fixedInVersionthat names Node 25 or 26. Per NVD, the Node 24 line fixed them at 24.14.1, 24.17.0 and 24.19.0, all at or below the 24.21.0 this image runs. The baseline shows the same effect: it reports CVE-2026-21637 against 24.14.0, which NVD records as fixed in 24.13.0.One environment note: a local
docker buildbehind Cloudflare Gateway fails on TLS, because the proxy CA is absent from the container trust store. That predates this change:pnpm db:generateinbuildalready failed the same way.🤖 Generated with dx-create-pr