BP#1: Minimal Base Images
Best Practice #1: Minimal Base Images
Less OS surface = fewer CVEs = smaller attack window.
Most teams default to a full base image like node:18 because it "just works". But every package in that image is a potential CVE vector — and the difference between a full and slim image is dramatic.
The comparison at a glance
| Image | Size | Packages | CVEs |
|---|---|---|---|
node:25 (full) |
1.63 GB | 693 | 242 |
node:lts-slim |
344 MB | ~272 | 34 |
node:25-slim |
322 MB | 272 | 30 |
node:alpine |
239 MB | ~150 | 34 |
dhi.io/node:25 |
~50 MB | 1 | 7* |
*6 of 7 have upstream fixes pending. 0 critical, 0 high.
Update the Dockerfile base image
Open catalog-service-node/Dockerfile and replace the existing content with this:
###########################################################
# Stage: base
###########################################################
FROM node:25-slim AS base
WORKDIR /usr/local/app
RUN useradd -m appuser && chown -R appuser /usr/local/app
USER appuser
COPY --chown=appuser:appuser package.json package-lock.json ./
###########################################################
# Stage: dev
###########################################################
FROM base AS dev
ENV NODE_ENV=development
RUN npm install
CMD ["yarn", "dev-container"]
###########################################################
# Stage: final
###########################################################
FROM base AS final
ENV NODE_ENV=production
RUN npm ci --production --ignore-scripts && npm cache clean --force
COPY ./src ./src
EXPOSE 3000
CMD ["node", "src/index.js"]
The single critical change:
- FROM node:18 AS base
+ FROM node:25-slim AS base
Rebuild and re-scan
docker build -t catalog-service:slim --sbom=true --provenance=mode=max .
Compare image sizes:
docker images catalog-service
IMAGE ID DISK USAGE CONTENT SIZE
catalog-service:latest 48806e62b871 1.62GB 413MB
catalog-service:slim 8d03cef7a79f 368MB 84.1MB
Now re-run the Scout quickview:
docker scout quickview catalog-service:slim --org <YOUR_ORG>
Target │ catalog-service:slim │ 0C 2H 2M 24L
Base image │ node:25-slim │ 0C 1H 2M 24L
One FROM change. Result:
- ✅ 2 critical eliminated
- ✅ 25 high eliminated
- ✅ Image 4× smaller
Continue to BP#2: Multi-Stage Builds.