the agent marked a CVE fixed, but the rescan still flagged it - the patch bumped the wrong package in a multi-stage...
Fixes a CVE that a rescan still flags after patching, because the patch bumped the package in the builder stage while the vulnerable copy ships in the final stage. Use it when the lockfile shows the fixed version but the scanner keeps reporting the CVE on the built image. Key trigger: the installed package version differs between build stages of a multi-stage Dockerfile.
TL;DR: Verify the package version in the final runtime stage, not just the builder - the vulnerable copy is the one that ships. Bumping the version in the lockfile or builder stage changes nothing if the final stage installs its own copy or inherits an old base layer. Rebuild with a clean cache on the final stage and confirm the installed version inside the running image before closing the CVE.
rescan: CVE-2026-XXXXX still present in image (lockfile shows fixed version 1.2.4)- Inspect the installed version inside the final image: run the image and query the package manager (for example
pip show [package]or the OS package list). Expected: you see the OLD vulnerable version, proving the runtime copy was never updated. - Find where the final stage gets the package: read the Dockerfile stages and check whether the final stage runs its own install, copies artifacts from the builder, or inherits the package from the base image. Expected: you identify the stage that actually places the vulnerable files.
- Apply the bump in the right stage: update the base image tag, the final-stage install line, or the copy from the builder - whichever owns the runtime copy. Expected: the Dockerfile change touches the stage that ships.
- Rebuild with a clean layer cache for the affected stages and re-scan. Expected: the rescan no longer reports the CVE.
- Close the ticket only after the rescan of the rebuilt image is clean, not when the lockfile changes. Expected: ticket closure is gated on scanner evidence from the shipped artifact.
Use this when
- a rescan flags a CVE the patch supposedly fixed
- the lockfile and the image disagree on package versions
- multi-stage Dockerfiles separate build and runtime
- the scanner attributes the CVE to a specific layer or path
Not for this skill when
- the scanner flags a different CVE than the one patched
- the patch itself failed to apply anywhere
- the vulnerable package lives in a sidecar or base image you do not build
- the CVE is a scanner false positive on the fixed version
Variant phrasings
- CVE still flagged after upgrade
- patch bumped wrong stage docker build
- rescan shows old package version after fix
- fixed in builder but not in final image
Why it happens
Multi-stage builds separate build-time and runtime environments. The lockfile or builder stage gets the fixed version, but the final stage installs its own copy from a base image or an unpinned install line, so the shipped artifact still carries the vulnerable package while every source-side check looks clean.
Edge cases
- cached layers can resurrect the old package - a no-cache rebuild of the final stage is the real test
- distroless or minimal base images bundle the package where no package manager can see it - match the scanner's reported file path
- the CVE may be flagged against a second copy of the same library (system vs vendored) - fix the copy the scanner names
- base image bumps can reintroduce the old package later - the rescan gate must run on every build, not just the patch build
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_9RyBEF9AncDthBEcoA1uHQ
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.