diff --git a/.trivyignore b/.trivyignore index 3b67c38..98984b9 100644 --- a/.trivyignore +++ b/.trivyignore @@ -1,12 +1,13 @@ # Trivy CVE Suppressions — Upstream Dependencies -# Reviewed: 2026-02-12 | Milestone: M11-CIPipeline +# Reviewed: 2026-02-13 | Milestone: M11-CIPipeline # -# MITIGATED in this sprint: +# MITIGATED: # - Go stdlib CVEs (6): gosu rebuilt from source with Go 1.26 # - npm bundled CVEs (5): npm removed from production Node.js images +# - Node.js 20 → 24 LTS migration (#367): base images updated # -# REMAINING: OpenBao only (5 CVEs — 4 false positives + 1 upstream Go stdlib) -# Re-evaluate when upgrading openbao image beyond 2.5.0. +# REMAINING: OpenBao (5 CVEs) + Next.js bundled tar (3 CVEs) +# Re-evaluate when upgrading openbao image beyond 2.5.0 or Next.js beyond 16.1.6. # === OpenBao false positives === # Trivy reads Go module pseudo-version (v0.0.0-20260204...) from bin/bao @@ -16,19 +17,15 @@ CVE-2024-9180 # HIGH: privilege escalation (fixed in 2.0.3) CVE-2025-59043 # HIGH: DoS via malicious JSON (fixed in 2.4.1) CVE-2025-64761 # HIGH: identity group root escalation (fixed in 2.4.4) -# === npm bundled tar CVEs (not upgradeable — not our dependency) === -# Why suppressed instead of fixed: -# - tar@7.5.2 is bundled INSIDE npm, which ships with the node:20-alpine base image -# - It is NOT in pnpm-lock.yaml — not a direct or transitive app dependency -# - We already remove npm from all production images: -# `RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx` -# - Locally-built images have zero tar packages (verified via Trivy scan 2026-02-12) -# - CVEs may reappear in CI due to Docker layer caching of the base image -# To fully eliminate: switch to a distroless/slim base image without npm, or -# wait for Node.js 20 to bundle a patched npm release. -CVE-2026-23745 # HIGH: tar arbitrary file overwrite via unsanitized linkpaths -CVE-2026-23950 # HIGH: tar arbitrary file overwrite via Unicode path collision -CVE-2026-24842 # HIGH: tar arbitrary file creation via hardlink path traversal +# === Next.js bundled tar CVEs (upstream — waiting on Next.js release) === +# Next.js 16.1.6 bundles tar@7.5.2 in next/dist/compiled/tar/ (pre-compiled). +# This is NOT a pnpm dependency — it's embedded in the Next.js package itself. +# Affects web image only (orchestrator and API are clean). +# npm was also removed from all production images, eliminating the npm-bundled copy. +# To resolve: upgrade Next.js when a release bundles tar >= 7.5.7. +CVE-2026-23745 # HIGH: tar arbitrary file overwrite via unsanitized linkpaths (fixed in 7.5.3) +CVE-2026-23950 # HIGH: tar arbitrary file overwrite via Unicode path collision (fixed in 7.5.4) +CVE-2026-24842 # HIGH: tar arbitrary file creation via hardlink path traversal (needs tar >= 7.5.7) # === OpenBao Go stdlib (waiting on upstream rebuild) === # OpenBao 2.5.0 compiled with Go 1.25.6, fix needs Go >= 1.25.7. diff --git a/.woodpecker/api.yml b/.woodpecker/api.yml index ffb6628..90ef697 100644 --- a/.woodpecker/api.yml +++ b/.woodpecker/api.yml @@ -17,7 +17,7 @@ when: - ".woodpecker/api.yml" variables: - - &node_image "node:20-alpine" + - &node_image "node:24-alpine" - &install_deps | corepack enable pnpm install --frozen-lockfile diff --git a/.woodpecker/orchestrator.yml b/.woodpecker/orchestrator.yml index 6675d47..2d15af5 100644 --- a/.woodpecker/orchestrator.yml +++ b/.woodpecker/orchestrator.yml @@ -17,7 +17,7 @@ when: - ".woodpecker/orchestrator.yml" variables: - - &node_image "node:20-alpine" + - &node_image "node:24-alpine" - &install_deps | corepack enable pnpm install --frozen-lockfile diff --git a/.woodpecker/web.yml b/.woodpecker/web.yml index cda381e..d3f38a1 100644 --- a/.woodpecker/web.yml +++ b/.woodpecker/web.yml @@ -17,7 +17,7 @@ when: - ".woodpecker/web.yml" variables: - - &node_image "node:20-alpine" + - &node_image "node:24-alpine" - &install_deps | corepack enable pnpm install --frozen-lockfile diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 1179f5c..6a6ce5a 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -2,7 +2,7 @@ # Enable BuildKit features for cache mounts # Base image for all stages -FROM node:20-alpine AS base +FROM node:24-alpine AS base # Install pnpm globally RUN corepack enable && corepack prepare pnpm@10.27.0 --activate @@ -53,10 +53,9 @@ RUN pnpm turbo build --filter=@mosaic/api --force # ====================== # Production stage # ====================== -FROM node:20-alpine AS production +FROM node:24-alpine AS production -# Remove npm (unused in production — we use pnpm) to eliminate bundled CVEs -# (cross-spawn CVE-2024-21538, glob CVE-2025-64756, tar CVE-2026-23745/23950/24842) +# Remove npm (unused in production — we use pnpm) to reduce attack surface RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx # Install dumb-init for proper signal handling diff --git a/apps/orchestrator/Dockerfile b/apps/orchestrator/Dockerfile index 0722743..4909902 100644 --- a/apps/orchestrator/Dockerfile +++ b/apps/orchestrator/Dockerfile @@ -2,7 +2,7 @@ # Enable BuildKit features for cache mounts # Base image for all stages -FROM node:20-alpine AS base +FROM node:24-alpine AS base # Install pnpm globally RUN corepack enable && corepack prepare pnpm@10.27.0 --activate @@ -57,7 +57,7 @@ RUN find ./apps/orchestrator/dist \( -name '*.spec.js' -o -name '*.spec.js.map' # ====================== # Production stage # ====================== -FROM node:20-alpine AS production +FROM node:24-alpine AS production # Add metadata labels LABEL maintainer="mosaic-team@mosaicstack.dev" @@ -68,8 +68,7 @@ LABEL org.opencontainers.image.vendor="Mosaic Stack" LABEL org.opencontainers.image.title="Mosaic Orchestrator" LABEL org.opencontainers.image.description="Agent orchestration service for Mosaic Stack" -# Remove npm (unused in production — we use pnpm) to eliminate bundled CVEs -# (cross-spawn CVE-2024-21538, glob CVE-2025-64756, tar CVE-2026-23745/23950/24842) +# Remove npm (unused in production — we use pnpm) to reduce attack surface RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx # Install wget and dumb-init diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index e58f268..84a66e5 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -2,7 +2,7 @@ # Enable BuildKit features for cache mounts # Base image for all stages -FROM node:20-alpine AS base +FROM node:24-alpine AS base # Install pnpm globally RUN corepack enable && corepack prepare pnpm@10.27.0 --activate @@ -75,10 +75,9 @@ RUN mkdir -p ./apps/web/public # ====================== # Production stage # ====================== -FROM node:20-alpine AS production +FROM node:24-alpine AS production -# Remove npm (unused in production — we use pnpm) to eliminate bundled CVEs -# (cross-spawn CVE-2024-21538, glob CVE-2025-64756, tar CVE-2026-23745/23950/24842) +# Remove npm (unused in production — we use pnpm) to reduce attack surface RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx # Install pnpm (needed for pnpm start command) diff --git a/package.json b/package.json index 5f14630..7725f4b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "packageManager": "pnpm@10.19.0", "engines": { - "node": ">=20.0.0" + "node": ">=24.0.0" }, "scripts": { "build": "turbo run build",