To find which Dockerfile step added a vulnerable package, list the image history, match the layer that added the package by its command and size, then check whether that step is yours or came from the base image. Steps from the base image are fixed by changing the base. Steps from your Dockerfile are fixed in your file.
Start with the history
The docker image history command shows how an image was built: one row per layer with the command that created it, its size and a comment. The Docker reference says the output can be given in full with the no truncate option, which you need because the create command is cut short by default.
docker history --no-trunc --format 'table {{.CreatedBy}}\t{{.Size}}' myapp@sha256:abc123
Read from the bottom. The lowest rows are the base image's own steps, and the top rows are your Dockerfile steps in reverse order.
Match the package to a row
- Note the package name from the finding. If your scanner reports a layer digest, use it.
- Find the row whose command installs it. A package install command naming the package is the obvious match.
- If no row names it, the package arrived as a dependency of something else, or it was already in the base. Look at large rows near the bottom.
| What you see | Meaning | Fix lives in |
|---|---|---|
| Install command in a top row naming the package | You installed it | Your Dockerfile |
| Install command naming a different package | Pulled in as a dependency | Remove the parent or pin differently |
| Row from the base's own steps | Inherited | The base image or its tag |
| No row matches | Possibly a copied file or a compiled artifact | Your build output |
Limits of history
History records commands, not file lists, and a base image built elsewhere may show few or no commands. Multi-stage builds also drop earlier stages, so the final image's history shows just the last stage. If you need file level detail, a scanner or SBOM that records the layer for each package is more precise. The OCI specification describes layers as filesystem changesets applied in order, so each package file belongs to one layer in the sequence. See what a container image layer is.
Remember that history can also show what you built with. Commands and arguments are visible to anyone who can pull the image, which matters for secrets. See Docker history explained.
After you know the step
- Your step: update, pin or remove the package, then rebuild. See remove or patch.
- Base step: bump the base tag with a fresh pull. See fix base findings first.
- Unclear: ask for an SBOM from the build, which lists packages with their sources.
Record the answer in the ticket so the next engineer does not repeat the trace.
Where Safeguard fits
Safeguard's SBOM and dependency scanning lists components per image so you can match a finding to its origin, and policies can require an approved base. Free scan: gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen. Look for where each package came from.
Quick check
Why is the command text cut off in the history output?
By default long commands are truncated. Use the no truncate option to see the full text.
Does history work on a multi-stage image?
It shows the final stage alone. Earlier stages are not part of the shipped image.
Sources
Last reviewed: 19 October 2026.