# QA Audit Report — Dockerfile npm CVE Remediation **Date:** 2026-03-16 **Scope:** `Dockerfile` — `frontend-builder` stage npm upgrade to address 6 HIGH CVEs in `node:24.14.0-alpine` **Reviewer:** QA Security Agent --- ## Overall Verdict: APPROVED All structural, linting, and security gates pass. The change is correctly scoped to the build-only `frontend-builder` stage and introduces no new attack surface in the final runtime image. --- ## Changes Under Review | Element | Location | Description | |---|---|---| | `ARG NPM_VERSION=11.11.1` | Line 30 (global ARG block) | Pinned npm version with Renovate comment | | `ARG NPM_VERSION` | Line 105 (frontend-builder) | Bare re-declaration to inherit global ARG into stage | | `# hadolint ignore=DL3017` | Line 106 | Lint suppression for intentional `apk upgrade` | | `RUN apk upgrade --no-cache && ...` | Lines 107–109 | Three-command RUN: OS patch + npm upgrade + cache clear | | `RUN npm ci` | Line 111 | Unchanged dependency install follows the new RUN block | --- ## Gate Summary | # | Gate | Result | Details | |---|---|---|---| | 1 | Global `ARG NPM_VERSION` present with Renovate comment | **PASS** | Line 30; `# renovate: datasource=npm depName=npm` at line 29 | | 2 | `ARG NPM_VERSION` bare re-declaration inside stage | **PASS** | Line 105 | | 3 | `# hadolint ignore=DL3017` on own line before RUN block | **PASS** | Line 106 | | 4 | RUN block — three correct commands | **PASS** | Lines 107–109: `apk upgrade --no-cache`, `npm install -g npm@${NPM_VERSION} --no-fund --no-audit`, `npm cache clean --force` | | 5 | `RUN npm ci` still present and follows new block | **PASS** | Line 111 | | 6 | FROM line unchanged | **PASS** | `node:24.14.0-alpine@sha256:7fddd9ddeae8196abf4a3ef2de34e11f7b1a722119f91f28ddf1e99dcafdf114` | | 7 | `${NPM_VERSION}` used (no hard-coded version) | **PASS** | Confirmed variable reference in install command | | 8 | Trivy config scan (HIGH/CRITICAL) | **PASS** | 0 misconfigurations | | 9 | Hadolint (new code area) | **PASS** | No errors or warnings; only pre-existing `info`-level DL3059 at unrelated lines | | 10 | Runtime image isolation | **PASS** | Only `/app/frontend/dist` artifacts copied into final image via line 535 | | 11 | `--no-audit` acceptability | **PASS** | Applies only to the single-package global npm upgrade; `npm ci` is unaffected | | 12 | `npm cache clean --force` safety | **PASS** | Safe cache clear between npm tool upgrade and dependency install | --- ## 1. Dockerfile Structural Verification ### Global ARG block (lines 25–40) ``` 29: # renovate: datasource=npm depName=npm 30: ARG NPM_VERSION=11.11.1 ``` Both the Renovate comment and the pinned ARG are present in the correct order. Renovate will track `npm` releases on `datasource=npm` and propose version bumps automatically. ### frontend-builder stage (lines 93–115) ``` 93: FROM --platform=$BUILDPLATFORM node:24.14.0-alpine@sha256:... AS frontend-builder ... 105: ARG NPM_VERSION 106: # hadolint ignore=DL3017 107: RUN apk upgrade --no-cache && \ 108: npm install -g npm@${NPM_VERSION} --no-fund --no-audit && \ 109: npm cache clean --force ... 111: RUN npm ci ``` All structural requirements confirmed: bare re-declaration, lint suppression on dedicated line, three-command RUN, and unmodified `npm ci`. --- ## 2. Security Tool Results ### Trivy config scan **Command:** `docker run aquasec/trivy config Dockerfile --severity HIGH,CRITICAL` ``` Report Summary ┌────────────┬────────────┬───────────────────┐ │ Target │ Type │ Misconfigurations │ ├────────────┼────────────┼───────────────────┤ │ Dockerfile │ dockerfile │ 0 │ └────────────┴────────────┴───────────────────┘ ``` No HIGH or CRITICAL misconfigurations detected. ### Hadolint **Command:** `docker run hadolint/hadolint < Dockerfile` Findings affecting the new code: **none**. Pre-existing `info`-level findings (unrelated to this change): | Line | Rule | Message | |---|---|---| | 78, 81, 137, 335, 338 | DL3059 info | Multiple consecutive RUN — pre-existing pattern | | 492 | SC2012 info | Use `find` instead of `ls` — unrelated | No errors or warnings in the `frontend-builder` section. --- ## 3. Logical Security Review ### Attack surface — build-only stage The `frontend-builder` stage is strictly a build artifact producer. The final runtime image receives only compiled frontend assets via a single targeted `COPY`: ``` COPY --from=frontend-builder /app/frontend/dist /app/frontend/dist ``` The Alpine OS packages upgraded by `apk upgrade --no-cache`, the globally installed npm binary, and all `node_modules` are confined to the builder layer and never reach the runtime image. The CVE remediation has zero footprint in the deployed container. ### `--no-audit` flag `--no-audit` suppresses npm audit output during `npm install -g npm@${NPM_VERSION}`. This applies only to the single-package global npm tool upgrade, not to the project dependency installation. `npm ci` on line 111 installs project dependencies from `package-lock.json` and is unaffected by this flag. Suppressing audit during a build-time tool upgrade is the standard pattern for avoiding advisory database noise that cannot be acted on during the image build. ### `npm cache clean --force` Clears the npm package cache between the global npm upgrade and the `npm ci` run. This is safe: it ensures the freshly installed npm binary is used without stale cache entries left by the older npm version bundled in the base image. The `--force` flag suppresses npm's deprecation warning about manual cache cleaning; it does not alter the clean operation itself. --- ## Blocking Issues None.