Base Image CVE Maintenance
Recurring maintenance for the OS-level CVE volume reported by Trivy on the Docker images (SUP-002, 2026-07 security audit). This is a cadence, not an incident response: base images are pinned by digest (reproducible builds) which also freezes their OS CVEs until the digest is bumped.
When to use
- Scheduled base-image refresh (recommended monthly, or on a published CVE with a fix that affects a package we actually use).
- Trivy / Dependabot flags a HIGH/CRITICAL on the
php,pwa, orprovisionerimage.
Diagnosis
# Build the prod images: `make build` (php, pwa), plus the profiled provisioner:
# docker compose -f compose.yaml --profile provisioning build provisioner
trivy image --severity HIGH,CRITICAL bike-trip-planner-php:ci
trivy image --severity HIGH,CRITICAL bike-trip-planner-pwa:ci
trivy image --severity HIGH,CRITICAL bike-trip-planner-provisioner:prod
Read the Status column, not the raw count. The bulk of the volume on the
Debian Bookworm bases (perl, python3.x, zlib1g, curl, libssh2, acl,
linux-libc-dev, ...) is will_not_fix / fix_deferred / affected — no
upstream patch exists, so a rebuild cannot clear them. The actionable subset is
only the rows with Status: fixed. Triage those; ignore the won't-fix noise.
Procedure
-
Bump the digest of the affected base to the latest published for its tag:
.docker/php/Dockerfile-dunglas/frankenphp:1-php8.5@sha256:...anddunglas/frankenphp:1-builder-php8.5@sha256:.... Bump both together: the builder stage recompiles the FrankenPHP binary (Mercure protocol 1.0) and its libphp must match the runtime image..docker/pwa/Dockerfile-node:26@sha256:....docker/provisioner/Dockerfile-php:8.5-cli-bookworm@sha256:...(threeFROMlines, same digest).
docker pull dunglas/frankenphp:1-php8.5 docker inspect --format='{{index .RepoDigests 0}}' dunglas/frankenphp:1-php8.5 -
Rebuild and re-scan (the build and Trivy commands above); confirm the
fixed-status rows dropped. - Run the full suite (
make test) — a base bump can shift a system library.
Verification and follow-up
- The
osmium-tooldecision keeps the provisioner on Bookworm (no Alpine migration — osmium has no prebuilt Alpine binary). Distroless is only viable for stages that don't need osmium/osm2pgsql. - Note in the PR which
fixedCVEs were actually cleared vs. the won't-fix volume that remains by design.