Safeguard scans a container image by reading its layers and listing what is actually installed: OS packages from apt, yum and apk, language dependencies, and known components in compiled binaries. It matches each one against vulnerability data, adds EPSS and CISA KEV context, and keeps the image under daily rescans. Container image scanning is part of Safeguard SCA, which is GA.
The useful part is knowing which findings came from the base image you inherited, which from packages your Dockerfile added, and which from your application dependencies, because each is fixed by a different person in a different file. This post covers each layer, the documented commands, fixes, and where the scan stops.
Key takeaways
- Container image scanning is part of SCA (GA). Safeguard's docs say it scans container layers to identify dependencies and vulnerabilities, covering base image layers, OS package managers, application dependencies and embedded binaries.
- Three ways in, all GA. A registry integration in the app (with daily continuous scanning),
safeguard scan --imagefrom the Safeguard CLI on your own machine, andsafeguard ci scan --imageas a pipeline step. - Image scans see what is installed, not what is declared. OS packages appear only in image scans. Build-time-only dependencies dropped by a multi-stage build do not appear, which is correct.
- Prioritisation (GA) uses severity, EPSS and KEV for every finding. Reachability analysis (GA) is documented per programming language. The docs do not list OS package managers in the reachability table, so treat OS package findings as ranked by exploitability and exposure, not by call path.
- Fixes depend on the layer. Base image findings are fixed by rebuilding on a newer base. OS packages you installed are fixed in your Dockerfile. Application dependencies can get fix pull requests from autonomous remediation (GA, ships switched off with every category set to Manual).
- SBOM export (GA) in SPDX and CycloneDX covers the image, so the inventory you scanned is the inventory you can hand on.
- Self-healing containers (GA) can rebuild and promote images for you. Start it in advisory mode, where each rebuild arrives as a pull request you review.
- Policies and gates (GA) decide what fails. The plain
safeguard scancommand never fails on findings.
Why scan the image and not just the repository?
A repository scan reads your manifests and lockfiles. That tells you what your application asked for. It does not tell you what the operating system underneath it contains, because nothing in package.json or go.mod mentions the OpenSSL, glibc, zlib or curl that came with your base image.
Safeguard's container FAQ puts the difference in a short table. A source scan reads package manifests in source and finds declared dependencies. An image scan reads installed packages in image layers and finds what was actually installed. Source scans do not see OS packages. Image scans do. Build-only dependencies show up in a source scan but are excluded from an image scan because they are not in the final image.
Both views are true. The repository scan answers "what does my code depend on?" The image scan answers "what am I about to run?"
What NIST SP 800-190 says about image vulnerabilities
NIST Special Publication 800-190, the Application Container Security Guide, is the standard most container security programmes start from. Section 3.1.1, "Image vulnerabilities", makes the core point plainly: images are effectively static archives, so components inside them go out of date. An image built today with current packages will, at some point, contain components with newly discovered vulnerabilities. Because containers are not patched in the field, the guide says updates have to be made upstream in the images, which are then redeployed.
Section 4.1.1 gives the countermeasures. NIST asks for tools built for the pipeline and immutable image model, with three key traits:
- Integration with the whole image lifecycle, from the build, through the registries you use, to runtime.
- Visibility into vulnerabilities at all layers of the image, "not just the base layer", including application frameworks and custom software.
- Policy-driven enforcement, with quality gates at each stage of build and deployment so only images that meet your vulnerability policy progress.
Those three points map onto what follows: scan in the build and in the registry, see every layer, and gate on policy. Sections 3.1.2 to 3.1.5 list other image risks, such as configuration defects and untrusted images. This post covers vulnerable components only.
How image layers work, per the OCI image spec
The Open Container Initiative image specification defines an image as a stack of layer changesets. The layer document says one or more layers are applied on top of each other to create a complete filesystem. Each changeset is a tar archive. Additions and modifications appear as files. Removals are recorded as "whiteout" entries, files whose names start with .wh., which tell the runtime to hide a path when the layers are applied.
Two practical consequences follow for scanning:
- What runs is the merged filesystem. A package installed in layer two and removed in layer five is not present when the container starts. A scanner that reports on the final filesystem will not list it, which matches what runs.
- What ships is every layer. The bytes of that removed package still sit inside layer two's tar archive in the registry. Anyone who pulls the image pulls them. That is one reason multi-stage builds, which never copy build tools into the final image at all, are a better habit than installing and then deleting.
A layer is also the unit you can attribute. Your FROM line pulls in the base image's layers unchanged. Each RUN, COPY and ADD instruction in your Dockerfile adds a layer on top. That ordering is what lets you separate inherited risk from risk you introduced, which the walkthrough below relies on.
Why OS package findings behave differently
Language ecosystems usually publish one upstream version per fix. Linux distributions often do not. Debian, Ubuntu and Alpine maintain their own security trackers and frequently backport a fix into the version they already ship, under a distribution-specific package revision. Debian's Security Bug Tracker, for example, says its data comes from the Debian security team's own bug database, built from Debian Security Advisories, the CVE list, the NVD and Debian bug reports. Alpine publishes per-release security databases at secdb.alpinelinux.org. Ubuntu publishes its own CVE pages.
So an OS package finding has a few properties a library finding does not:
- The fixed version is a distribution revision, not an upstream release. "Upgrade OpenSSL to the next upstream release" is usually the wrong instruction inside a Debian or Alpine image.
- A distribution may mark a CVE as not affecting its build, or as a low priority it will not fix in a stable release. That is a judgement by the distribution's security team, and your scanner's result depends on whether its data reflects it.
- The fix normally arrives through a rebuilt base image or a package manager upgrade inside your build, not through a change to your application code.
Keep that in mind when you read the results. An OS package finding with no fixed version is common, and it is not always a sign the scanner is wrong.
What does Safeguard read inside an image?
Safeguard's container image docs list five things it analyses when scanning an image:
| What Safeguard analyses | What the docs say it finds |
|---|---|
| Base image layers | The parent image and its dependencies |
| Package managers | Packages installed with apt, yum, apk, npm, pip and others |
| Application dependencies | Libraries and frameworks |
| Configuration files | Manifest files and configs that identify components |
| Embedded binaries | Known components in compiled binaries, such as Go and Rust binaries |
The SCA docs add that the supported ecosystems include npm, pnpm, Yarn, PyPI, Maven, Gradle, Go modules, Cargo, NuGet, Composer and Ruby Bundler, "plus components discovered inside container image layers". The offering files describe SCA the same way: full transitive inventory across those ecosystems plus container layers, labelled GA.
A few behaviours from the container FAQ are worth knowing before your first scan:
- Distroless and minimal images work. The FAQ names the distroless static, base and Java images as supported, and notes they have fewer packages but can still carry vulnerable components.
- A scan with no dependencies is not always an error. On a scratch image, or one whose application is statically compiled, there may be no package database to read. The FAQ lists this as a known cause of an empty result.
- Multi-architecture images scan one platform at a time. By default Safeguard scans the platform matching the scanner, linux/amd64. To scan another, specify the platform in the image configuration or use a platform-specific tag.
- Windows container images are supported, and the FAQ warns they take longer because of their size.
- You do not need to pull images locally for registry scans. Safeguard connects to the registry and pulls the image on demand with the credentials you provide.
Why images often show more findings than the code
The FAQ answers this directly. Images include base OS packages with their own vulnerabilities, system libraries such as libc and OpenSSL, dependencies used during the build that are not in source, and sometimes an outdated base image. A team that has driven its repository findings close to zero is often surprised by the first image scan. That is expected. Most of the new findings are OS packages that were never visible before.
Three ways to get an image in front of Safeguard
All three routes below use GA surfaces: the app's Integrations page (part of ESSCM, GA), the Safeguard CLI (GA) and the CLI in CI (GA). They differ in where the image is read and what happens to the results. The published post on tracking container images per environment covers registry credentials, environment naming and fail thresholds in depth, so this section stays short and focuses on what each route means for layer analysis.
Route 1: a registry integration in the app
From Integrations, filter by Container Image. The Generate SBOM docs list Amazon ECR, Docker Hub, GCP Cloud Source and OCI Registry cards, and the docs have a separate page for Azure Container Registry. The CLI support matrix also lists GitHub Container Registry, GitLab Container Registry, Harbor, Quay.io and any generic OCI registry. Check the support matrix for the authentication method each registry expects.
For a public image, click Connect on the registry card, select the Public tab, enter the image reference (the docs use nginx:latest as the example), configure project settings and click Connect. For a private image, select the Private tab, enter registry credentials, click Verify Credentials, browse and select images, configure project settings and click Connect.
The registry route is the one that gives you continuous scanning. The Generate SBOM and Vulnerabilities docs say Safeguard rescans projects daily and re-evaluates them when new CVEs are published, with optional triggers on push, on a schedule or on release. An image you scanned clean last month will pick up a finding when a new CVE lands on one of its packages, without a rebuild.
Route 2: the Safeguard CLI on your own machine
The CLI docs describe safeguard scan as the command that builds an SBOM for a target, matches it against vulnerability databases and writes the results as JSON files under ./output. It takes exactly one target. For an image:
# A container image
safeguard scan --image nginx:latest
# A private registry
safeguard scan --image myregistry.azurecr.io/myapp:v1 \
--registry-username "$REGISTRY_USER" \
--registry-password "$REGISTRY_PASSWORD"
The usage docs say safeguard scan --image also reads local images, using the prefixes podman:<ref>, docker-archive:<file>, oci-archive:<file> and oci-dir:<dir>. That matters for two cases: scanning an image you have just built and not pushed, and scanning in an air-gapped network where the image arrives as a file.
Results include vuln.json, license.json and collection.json, among others, in a folder per scan. To see them in the platform next to your other projects, scan from the interactive terminal (/scan .) while signed in. The docs say the runner then uploads the SBOM and findings, never your source.
One behaviour to plan around: safeguard scan does not fail on findings. The docs say it exits 0 when the scan ran, 1 when the command itself failed, and 2 when results were written but the vulnerability scan did not actually run. There is no severity threshold flag on safeguard scan. Gating is done by policy gates in the platform, or by the CI command below.
Route 3: a step in your pipeline
The CI/CD container images page shows one step after your build:
safeguard ci scan --image "ghcr.io/acme/api:$TAG" --environment prod --wait --fail-on critical
The docs say this scans the image on the runner and records it in Safeguard under the image's repository, one version per environment and tag. The image is read from the local Docker daemon when the step runs where the image was built, or from a registry using SAFEGUARD_REGISTRY_USERNAME and SAFEGUARD_REGISTRY_PASSWORD as CI secrets. Only the results leave the runner. The API key needs the scans:trigger and scans:read scopes and is stored as SAFEGUARD_API_KEY.
--fail-on takes critical, high, medium or low and only applies with --wait. The commands in this post are copied from the docs pages linked in Sources. We have not run them in a pipeline for this post, so check safeguard <command> --help against your installed version. The CLI docs themselves say that where the page and --help disagree, --help is right.
Which route gives you which view?
| Route | Where the image is read | Results in the platform | Rescanned when new CVEs land | Fails a build |
|---|---|---|---|---|
| Registry integration (GA) | Safeguard pulls from your registry | Yes | Yes, daily continuous scanning | Through policies and gates |
safeguard scan --image (CLI, GA) | Your machine | Only when run signed in from the interactive terminal | No, it is a point in time scan | No, exits 0 on findings |
safeguard ci scan --image (CI, GA) | The CI runner | Yes, one version per environment and tag | Recorded project follows platform scanning | Yes, with --wait --fail-on |
Most teams end up with two of these: the CI step so a bad image never gets pushed or promoted, and the registry integration so images already in production keep getting checked.
Base image findings versus application layer findings
This is the question that decides who fixes what. An image's findings come from three places, and each has a different owner:
| Where the finding comes from | Typical examples | Who usually owns the fix | Where the fix happens |
|---|---|---|---|
The base image (your FROM line) | glibc, OpenSSL, zlib, ca-certificates, the distro's shell tools | Platform or base image owner | Bump or rebuild on a newer base image tag or digest |
| OS packages your Dockerfile installs | apt-get install curl, apk add imagemagick | The service team | The RUN line in your Dockerfile, then rebuild |
| Application dependencies | npm, PyPI, Maven, Go, Cargo, NuGet, Composer, Bundler packages | The service team | The manifest and lockfile in the repository, then rebuild |
| Compiled binaries copied in | A Go or Rust binary, a vendored tool | Whoever builds that binary | Rebuild the binary with updated dependencies |
Safeguard's docs say the image scan identifies the parent image and its dependencies from the base image layers. The docs do not describe a per-layer column in the findings view, so do not plan your triage around one. The method below gets you a clean split using only documented commands.
A documented way to split base image findings from your own
- Scan the base image on its own. Run
safeguard scan --imageagainst the exact base reference in yourFROMline, ideally by digest. Record it as its own project if you scan from the signed-in terminal, or connect it through a registry integration so it is rescanned daily. - Scan your built image. Use the CLI or the CI step, as above.
- Compare the two. Any finding present in both comes from the base. Any finding only in your image comes from your
RUNinstructions, your application dependencies or a binary you copied in. - Check application findings against the repository scan. If the same package and version also appears in your repository's SCA results, it is an application dependency and has a lockfile to fix. If it appears only in the image, it came from an OS package install or a binary.
The split also makes base image decisions measurable: when you test a slimmer base, scan it the same way and compare the counts. Pin the base by digest, which the FAQ recommends for production scanning, so the comparison describes the image you actually built on.
How Safeguard prioritises image findings
Every finding in the Vulnerabilities tab carries the same fields, whether it came from an OS package or a library. The Vulnerabilities docs list CVE ID, CVSS score, EPSS score, an Exploitable flag for known exploitation in the wild, the affected component and version, the fixed version, a description, references, and reachability. The tab groups findings as Critical, High, Medium, Low and Exploitable. Vulnerability management, including EPSS and KEV, is GA.
EPSS and KEV
FIRST describes EPSS as a model that estimates the probability that a published CVE will be exploited in the wild in the next 30 days, published daily for every CVE. CISA describes its Known Exploited Vulnerabilities catalog as the authoritative source of vulnerabilities exploited in the wild and says organisations should use it as an input to prioritisation. Safeguard's reachability docs say it ingests the daily EPSS feed and treats a KEV listing as evidence that exploitation is not hypothetical.
For base image findings this is the most useful ranking you have. A base image commonly carries many medium and low CVEs in system libraries. Very few of them are on KEV or have a high EPSS probability. Filtering on those two signals separates the handful that justify an emergency rebuild from the backlog that the next scheduled base image bump will clear.
The reachability docs show filters in the Vulnerabilities table, including kev:true for KEV-listed findings and epss:>0.3 for an EPSS probability above 30 percent. You can also filter by severity, CVSS range, EPSS range, exploitable status, component name, fix availability, reachability status and date range, per the Vulnerabilities docs. Fix availability is the filter base image owners use most: it separates "a newer package revision exists" from "the distribution has not shipped one".
For US federal agencies, note that CISA's BOD 22-01 remediation deadlines for KEV entries are history. BOD 26-04 (10 June 2026) supersedes it with risk-based timelines. Check the directive itself for current obligations.
Where reachability helps, and where it stops
Reachability analysis is GA. The reachability docs describe three kinds: static reachability from a call graph built from source, lockfile and bytecode; dynamic reachability from a runtime collector; and configuration reachability from framework configuration. A finding is classified Reachable, Conditionally reachable, Unreachable or Unknown. The docs say Unknown is marked conservatively as potentially reachable.
The docs list reachability support per programming language. They do not list OS package managers such as apt, yum or apk. Read that literally: for an OS package finding in a base image, do not expect a call path verdict. Rank those findings with severity, EPSS, KEV, fix availability and what the container is exposed to.
For the application dependencies inside the image, reachability works the same way it does on the repository. The language-specific posts in this series cover it per ecosystem, and the published post on prioritising with reachability, EPSS and KEV explains the scoring in general.
How to fix what an image scan finds
The fix depends entirely on which layer the finding came from. Work through them in this order, because fixing the base first often clears findings you would otherwise chase one by one.
1. Base image findings: rebuild on a newer base
Most OS package findings in a well-maintained base image are fixed by the image publisher within days of the distribution shipping a patched revision. Your job is to pick that up:
- Rebuild against the current digest of the same tag, if you are pinned to a moving tag such as
20-alpine. - Move to a newer tag or a newer distribution release if the old one has stopped receiving fixes.
- Move to a smaller base, such as a distroless or minimal image, if most of your findings are in tools your service never uses. The container FAQ recommends minimal base images and official images where possible.
After the rebuild, scan again and compare. The base image scan you set up earlier tells you whether the new base actually reduced the count before you roll it out.
Before you adopt a new base image, you can check it on Gold Open Source, which is free and needs no login. It shows affected and fixed versions for CVEs and packages. The published post on using Gold Open Source in your workflow covers the lookup, API and badges.
2. OS packages you installed: fix the Dockerfile
If a finding is only in your image and not in the base, and not in your repository scan, it came from a package your Dockerfile installs. Options, in order of preference:
- Remove it if the service does not need it at runtime. Many images carry compilers,
curlorgitleft over from a build step. - Move it to a build stage. Docker's multi-stage build docs describe using several
FROMstatements so that only the artifacts you copy reach the final stage. Anything left behind in a build stage never reaches the image you ship. - Upgrade it with the distribution's package manager in the same
RUNline that installs it, then rebuild.
3. Application dependencies: fix pull requests
Application dependencies inside the image are the same packages your repository scan sees. Fix them in the repository, not the image. Autonomous remediation (GA) can open a fix pull request that moves the dependency to a safe version, on one repository or in bulk with one pull request per repository. It ships switched off, with every category set to Manual, so nothing changes until your team turns it on and decides what still needs a human approval. The Vulnerabilities docs describe the in-app flow: click AI Remediate, review the proposed changes, then create the pull requests. You can also click a single vulnerability, select View Fix and review upgrade options with breaking change warnings.
Once the pull request merges, the next image build picks up the new lockfile. The published post on autonomous remediation in Safeguard explains the categories and strategies.
4. When there is no fix
OS package findings often have no fixed revision yet, or the distribution has decided not to fix them in a stable release. The Vulnerabilities docs offer two documented actions: Mark False Positive with a justification, and Accept Risk with an expiration date and a business justification, both submitted for approval where policy requires it. Use an expiry date every time, so the decision is reviewed when the distribution's position changes.
If you need to tell customers that a CVE in your image does not affect your product, a VEX statement is the right format. The published post on ingesting and sharing VEX and CSAF in Safeguard covers that flow.
5. Self-healing containers (GA)
Safeguard's docs describe self-healing containers as a loop that detects a new CVE in an image, plans a patch, rebuilds the image with your tests and promotes it, in an advisory mode that opens a pull request or in autonomous modes. Start in advisory mode, so each rebuild arrives as a pull request you can review, and keep the manual rebuild process above as your fallback. Confirm which registries and pipelines it supports for your account before you widen it.
Export the image SBOM
Every image scan produces an SBOM. SBOM generation and analysis is GA, in SPDX and CycloneDX. The CLI support matrix lists output formats including CycloneDX JSON and XML, SPDX JSON, tag-value and RDF, CSV, a custom JSON format, SARIF and JUnit XML.
CISA's SBOM resources describe an SBOM as a key building block of software security and supply chain risk management. CycloneDX and SPDX are the two formats most buyers and regulators expect. For images, the SBOM is particularly useful because it lists the OS packages that no repository SBOM will ever contain. If a customer asks whether your product ships a vulnerable version of a system library, the image SBOM answers it.
Two practical notes:
- Keep the SBOM with the image version. The CI step records one version per environment and tag. Export from that version so the SBOM and the image that shipped stay paired.
- Validate before you share. The CLI's
safeguard validatecommand checks CycloneDX, SPDX and VEX documents against their specifications, with--strictto treat warnings as errors.
For the wider SBOM picture, including NTIA minimum elements and the EU Cyber Resilience Act, see the published post on SBOM generation and analysis in Safeguard.
Step by step: scan an image, split the findings, fix and keep it clean
This walkthrough uses only commands and screens from the docs pages listed in Sources. We have not run these snippets in your environment, so check --help on your installed CLI before you script them.
-
Install the CLI. On macOS and Linux:
curl -fsSL https://cli.safeguard.sh/install | bashOn Windows, the docs show
irm https://cli.safeguard.sh/install.ps1 | iex. The CLI is a single static binary with no separate runtime. -
Sign in. Run
safeguardto open the interactive terminal and type/login, or runsafeguard loginfrom the command line. On a machine with no browser,safeguard login --no-browserprints a URL and code to enter elsewhere. -
Build your image locally and scan it before pushing. The container FAQ shows this pattern:
# Build image locally docker build -t myapp:test . # Scan local image safeguard scan --image myapp:test # If scan passes, push to registry docker push myregistry.com/myapp:testResults land in
./outputas JSON, includingvuln.json,license.jsonandcollection.json. Remember that "passes" here is your judgement after reading the results. The command exits 0 whether or not it found vulnerabilities. -
Scan the base image on its own. Take the exact reference from your
FROMline and scan it the same way. Use the digest form if you have it. The FAQ listsnginx@sha256:...style references as supported. -
Compare the two result sets. Findings in both are inherited from the base. Findings only in your image belong to your Dockerfile or your application. Hand the base image list to whoever owns your base images, and keep the rest.
-
Connect the registry for continuous scanning. In the app, go to Integrations, filter by Container Image, click Connect on your registry, choose Public or Private, verify credentials for a private registry, select the images and click Connect. Use specific version tags or digests, not
latest, which the docs list as a best practice. -
Add the CI step so unscanned images do not get promoted. Create an API key with
scans:triggerandscans:read(admins can do this in the Set up CI/CD sheet or under Settings › Developer), store it asSAFEGUARD_API_KEY, and add the step after your build:safeguard ci scan --image "ghcr.io/acme/api:$TAG" --environment prod --wait --fail-on criticalUse one step per environment, each with its own
--environment. You might fail only on critical in production and set no--fail-onin development. -
Triage in the Vulnerabilities tab. Start with the Exploitable group and a
kev:truefilter. Then use the fix availability filter to separate findings with a fixed version from those without one. For application dependencies, add the reachability filter. For OS packages, rank by EPSS and exposure. -
Fix by layer. Rebuild on a newer base for inherited findings. Edit your Dockerfile for OS packages you installed. Fix application dependencies in the repository, by hand or with a fix pull request if your team has turned autonomous remediation on. Record accepted risk with an expiry date where no fix exists.
-
Rebuild, rescan and export. Rebuild the image, let the CI step scan it, confirm the findings you fixed are gone, and export the SBOM for that version in the format your customers or auditors expect.
-
Set the gate in the platform. Policies and gates are evaluated in the platform, not by the CLI. The gate actions in the docs are Block, Warn and Notify, with approvals handled through exceptions. The published post on plain English security policies to release gates walks through creating one.
Air-gapped and offline scanning
For an isolated network, the container FAQ describes exporting the image with docker save myimage:tag > image.tar and moving the file across. The CLI usage page says safeguard scan --image reads docker-archive:<file> and oci-archive:<file> references, and that safeguard update --import loads a vulnerability database downloaded elsewhere. The FAQ also shows an --image-file form. The two pages disagree on the flag, so use whichever your installed --help lists. Air-gapped deployment is GA in the offering files; confirm offline scanning is enabled for your account before you rely on it.
Requirement, what Safeguard does, and what you still own
| Requirement (source) | What Safeguard does | What you still own |
|---|---|---|
| Visibility into vulnerabilities at all image layers, not just the base (NIST SP 800-190 section 4.1.1) | Scans base image layers, OS packages, application dependencies and embedded binaries (SCA, GA) | Scanning every image you ship, including sidecars and job images |
| Integration across build, registry and runtime (NIST SP 800-190 section 4.1.1) | CLI scan before push, CI step per environment, registry integration with daily rescans (all GA) | Wiring the CI step into every pipeline that builds an image |
| Quality gates at each stage (NIST SP 800-190 section 4.1.1) | --fail-on in CI; policies and gates in the platform with Block, Warn and Notify (GA) | Choosing thresholds and owning the exception process |
| Images are fixed upstream and redeployed (NIST SP 800-190 section 3.1.1) | Shows the fixed version where one exists; fix pull requests for application dependencies (GA, ships off); self-healing containers (GA) | Rebuilding images, rolling them out, and retiring old running containers |
| Prioritise known exploited vulnerabilities (CISA KEV) | KEV and EPSS on every finding; kev:true and EPSS filters (GA) | Deciding response times; following BOD 26-04 if you are a federal agency |
| A machine-readable inventory of what ships (CISA SBOM resources, CycloneDX, SPDX) | SBOM export in SPDX and CycloneDX (GA); safeguard validate | Distributing SBOMs and keeping them paired with image versions |
Decision table: which route and fix fits your situation
| Your situation | Start here | Then |
|---|---|---|
| You have never scanned your images | safeguard scan --image on your top five production images | Connect the registry so they are rescanned daily |
| You build images in CI and want to stop bad ones | safeguard ci scan --image ... --wait --fail-on critical in the production pipeline | Add the step to staging and development without --fail-on |
| Most findings are in the base image | Scan the base image on its own and compare | Rebuild on a current digest, or test a minimal base |
| Findings are in packages your Dockerfile installs | Remove unused packages or move them to a build stage | Upgrade the rest in the same RUN line |
| Findings are in application dependencies | Fix in the repository; turn on autonomous remediation for that category if you want pull requests | Rebuild the image from the merged branch |
| A finding has no fixed version | Check KEV and EPSS, then Accept Risk with an expiry | Publish a VEX statement if customers ask |
| You run in an isolated network | docker save, then scan the archive reference with an imported database | Confirm offline mode is on your plan |
What Safeguard does not do
- It does not fix the base image for you by default. Autonomous remediation opens pull requests for application dependencies and ships switched off. Base image rebuilds are your pipeline's job today. Self-healing containers (GA) can automate them once you turn it on.
- It does not give a call path verdict for OS packages. The reachability docs list programming languages, not OS package managers. Base image findings are ranked by severity, EPSS, KEV and context, not by whether your code calls the vulnerable function.
- It does not replace your distribution's security tracker. Whether a Debian or Alpine package revision contains a backported fix is decided by that distribution. When a finding and the distribution's own tracker disagree, check the tracker and record your decision.
- A clean component scan is not a hardened image. NIST SP 800-190 lists other image risks in sections 3.1.2 to 3.1.5. This post covers vulnerable components only. Running as root, open ports and image signing need their own controls.
- It does not scan every architecture at once. The default is linux/amd64. Multi-architecture images need a platform setting or platform-specific tags per architecture you ship.
- The plain CLI scan does not fail builds.
safeguard scanexits 0 on findings. Use the CI command with--wait --fail-on, or platform gates. - It does not see what is not in the image. Host kernels, the container runtime, Kubernetes node software and anything mounted at runtime are outside the image and outside the scan.
- It does not guarantee a fix exists. Many OS package CVEs have no fixed revision in a stable release. Safeguard shows that honestly as a finding with no fixed version.
Common mistakes
- Scanning
latest. A tag that moves means last week's result describes a different image. Scan by version tag or digest, which the FAQ recommends for production. - Treating the image count as the team's backlog. Most findings in a fresh image scan belong to the base. Split them first, or the service team spends a week on glibc.
- Installing then deleting build tools in later layers. The OCI layer model keeps the earlier layer's bytes in the image even after a whiteout hides them. Use a multi-stage build instead.
- Expecting reachability to clear OS findings. It is documented per language. Use KEV, EPSS and fix availability for the base layer.
- Reading exit code 0 as a pass.
safeguard scanexits 0 when the scan ran, whatever it found. Exit code 2 means the vulnerability scan did not actually run, so do not treat that as clean either. - Scanning only amd64 when you ship arm64. If your production nodes run arm64, scan that platform too.
- Accepting risk with no expiry. A distribution's "will not fix" can change, and so can KEV. Put a date on every exception.
- Fixing application dependencies in the Dockerfile. Patching a library version inside a
RUNline leaves the repository lockfile wrong, and the next build reverts it. Fix the lockfile. - Forgetting sidecars, init containers and job images. They run in production too. Connect them the same way.
FAQ
How do I scan a Docker image with Safeguard?
Install the Safeguard CLI and run safeguard scan --image <reference>, for example safeguard scan --image nginx:latest. Add --registry-username and --registry-password for a private registry. Results are written as JSON under ./output. To keep scanning it as new CVEs appear, connect the registry from Integrations in the app.
Does Safeguard scan OS packages inside container images?
Yes. The docs say an image scan detects packages installed with apt, yum and apk, along with language packages and known components in compiled binaries. OS packages appear only in image scans, not in repository scans, because they are not declared in any manifest.
How do I tell which vulnerabilities come from the base image?
Scan the base image reference from your FROM line on its own, then scan your built image, and compare. Findings in both come from the base. The docs say the scan identifies the parent image from the base image layers, but they do not describe a per-layer column in the findings view, so the comparison is the reliable method.
Why does my container image have more vulnerabilities than my source code?
Safeguard's FAQ lists the reasons: base OS packages, system libraries such as libc and OpenSSL, dependencies used during the build that are not in source, and outdated base images. A repository scan never sees any of those.
Can Safeguard scan an image before I push it to a registry?
Yes. Build it locally, run safeguard scan --image myapp:test, and push only after you have reviewed the results. In a pipeline, safeguard ci scan --image reads the image from the local Docker daemon on the runner that built it.
Does reachability analysis work on container base images?
Reachability is documented per programming language, so it applies to the application dependencies inside your image. The docs do not list OS package managers in the reachability table. Rank base image findings by severity, EPSS, KEV and fix availability instead.
Can I export an SBOM from a container image scan?
Yes. SBOM generation is GA, and the CLI support matrix lists CycloneDX and SPDX outputs among others. The image SBOM includes OS packages, which a repository SBOM does not.
How do I fail a build on critical vulnerabilities in an image?
Use the CI command with --wait --fail-on critical. The plain safeguard scan command has no severity threshold and exits 0 on findings. For organisation-wide rules, set a policy gate in the platform.
Does Safeguard rebuild my images automatically?
Not by default. Self-healing containers (GA) can rebuild and promote images once you turn it on, starting in advisory mode. Autonomous remediation, which opens fix pull requests for application dependencies, is GA but ships switched off with every category set to Manual.
Try it on your own images
The fastest way to see your own split between base image and application findings is to scan one production image and its base side by side. Install the CLI from safeguard.sh/download, and keep the Safeguard docs open for the registry and CI pages.
Once you can see which findings are inherited and which are yours, the next question is how to close them quickly when a fix exists, and what to do when it does not. The section below is Safeguard's standard answer to that question for the dependencies and images you build.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The first demo is a real Safeguard CLI session. It installs the CLI, opens the interactive terminal, and asks the assistant to fix a lodash CVE in a repository: it reads the finding and advisory, asks before any command that changes something, edits package.json, runs the install and tests, and pushes nothing. That is the same flow you would use for an application dependency found inside an image, fixed in the repository and then rebuilt. It finishes with /scan ., the signed-in scan that uploads results to the platform.
Click through it at your own pace, or open it full screen.
The second demo sets up the local runner on your own machine, approves it with its device code, and scans from the terminal. For images, the same runner is how platform-assigned scan jobs run on a machine you control, with only the results leaving it, so you can try the image scan from this post on your own hardware.
Click through it at your own pace, or open it full screen.
Quick check
Your image scan shows 140 findings and your repository scan shows 9. Where do you start?
Scan the base image from your FROM line on its own and compare. Most of the difference is usually OS packages and system libraries inherited from the base. Hand those to the base image owner, rank them by KEV, EPSS and fix availability, and keep the findings that only appear in your image for the service team.
Your pipeline runs safeguard scan --image and the step is always green. Is the image clean?
Not necessarily. safeguard scan exits 0 whenever the scan ran, whatever it found. To fail on findings, use safeguard ci scan --image ... --wait --fail-on <severity> or a policy gate in the platform, and read the results in ./output or the Vulnerabilities tab.
Sources
- NIST SP 800-190, Application Container Security Guide (CSRC page)
- NIST SP 800-190 full text (PDF)
- OCI image spec: Image Layer Filesystem Changeset
- CISA Known Exploited Vulnerabilities Catalog
- FIRST: Exploit Prediction Scoring System
- CISA: Software Bill of Materials
- CycloneDX specification overview
- SPDX specifications
- NIST SP 800-218, Secure Software Development Framework
- Debian Security Bug Tracker
- Alpine Linux security database
- Ubuntu CVE reports
- Docker docs: Multi-stage builds
- Safeguard docs: Container Images
- Safeguard docs: Container Image Integration FAQ
- Safeguard docs: Amazon ECR
- Safeguard docs: CI/CD container images
- Safeguard docs: Safeguard CLI
- Safeguard docs: CLI usage
- Safeguard docs: CLI support matrix
- Safeguard docs: Generate SBOM
- Safeguard docs: Software Composition Analysis
- Safeguard docs: Vulnerabilities
- Safeguard docs: Vulnerability Prioritization (Reachability Analysis)
- Safeguard docs: Self-Healing Containers
- Gold Open Source
Last reviewed: 24 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.