Docker Hardened Images Series — Blog 3
What We Are Building
By the end of this blog you will:
- Inspect the signed attestations that every Docker Hardened Image carries
- Understand SBOM, provenance, signatures and VEX in practical terms
- Verify that an image really comes from Docker and has not been tampered with
- Scan your own application image
- Evaluate any image against the same policy bar that DHI images meet
This is the supply-chain transparency part of hardened images.
Why This Matters
A minimal image with few CVEs is good.
Knowing exactly what is inside it, how it was built, and being able to prove those claims is better.
Docker Hardened Images ship with:
- A signed Software Bill of Materials (SBOM)
- SLSA Build Level 3 provenance
- Cryptographic signatures
- VEX statements (which vulnerabilities are actually exploitable)
You can inspect and verify all of this yourself. You can also hold your own images to the same standard using the official DHI policy bundle.
What You Should Know Before Starting
- Blogs 1 and 2 completed
-
docker login dhi.ioalready done - Docker Scout available (included with Docker Desktop)
Core Concepts (Simple Explanations)
| Concept | What it answers | Why it matters |
|---|---|---|
| SBOM | What packages and versions are inside the image? | Transparency & vulnerability matching |
| Provenance | Who built it, from which source, with which steps? | Tamper resistance (SLSA) |
| Signature | Has this attestation been altered since Docker signed it? | Trust |
| VEX | Is this CVE actually exploitable in this image? | Reduce noise in scans |
Supply-chain Metadata Flow
Explanation
Docker builds the image and attaches signed attestations.
You (or your CI) can later pull those attestations and verify the signatures.
If the signature is valid, you know the metadata has not been changed.
Step 1 — List Attestations on a DHI
docker scout attest list dhi.io/python:3.13
Output
➜ dhi-lab docker scout attest list dhi.io/python:3.13
i New version 1.24.0 available (installed version is 1.23.1) at https://github.com/docker/scout-cli
✓ SBOM obtained from attestation, 100 packages found
✓ Provenance obtained from attestation
## Overview
│ Analyzed Image
──────────────┼───────────────────────────────────────────────────────
Subject │ dhi.io/python:3.13
digest │ 24a8822f76af
platform │ linux/arm64
provenance │ https://github.com/docker-hardened-images/definitions
│ 5fb32dbb43253700792f258345f151035442841c
size │ 26 MB
packages │ 100
## Attestations
https://cyclonedx.org/bom/v1.6 CycloneDX SBOM
sha256:cd84b3cc8ea0476ce46f0332d80c32559fb027a75c4e54c0e53d9e68d9c6335f
Name │ dhi.io/python
digest │ cd84b3cc8ea0
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://cyclonedx.org/bom/v1.6
https://docker.com/dhi/changelog/v0.1 Changelog
sha256:8d5f5d332cd3f4849aee647a6e3cd3656273364c8330b73a3204dd15ec2fb615
Name │ dhi.io/python
digest │ 8d5f5d332cd3
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://docker.com/dhi/changelog/v0.1
https://docker.com/dhi/source/v0.1
sha256:ff88fffcb43f8b1f1c097f03b3b7d0625456ee2b6c94c43609442ab77cdc07fa
Name │ dhi.io/python
digest │ ff88fffcb43f
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://docker.com/dhi/source/v0.1
https://in-toto.io/attestation/vulns/v0.2 in-toto vulnerabilities
sha256:37889af6f7e43d2c7990b75801624071f451bc62037faf64f2268fb00853cdea
Name │ dhi.io/python
digest │ 37889af6f7e4
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://in-toto.io/attestation/vulns/v0.2
https://openvex.dev/ns/v0.2.0 OpenVEX
sha256:613cdd6ab043d43ca77ffcf90aba336899a03d51a84c93f0bd5c620d0f7ca37a
Name │ dhi.io/python
digest │ 613cdd6ab043
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
com.docker.scout.vex.source │ exceptions
in-toto.io/predicate-type │ https://openvex.dev/ns/v0.2.0
https://scout.docker.com/provenance/v0.1 Scout provenance
sha256:6a19c4b87c703e42ae53005562088c95e1a94d6c72dd07d47e064935a3b9bfea
Name │ dhi.io/python
digest │ 6a19c4b87c70
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://scout.docker.com/provenance/v0.1
https://scout.docker.com/sbom/v0.1 Scout SBOM
sha256:586bc87d9734f37b0733973179241ec2f955fbed732dc38522e421f1f4c9b0d1
Name │ dhi.io/python
digest │ 586bc87d9734
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://scout.docker.com/sbom/v0.1
https://scout.docker.com/secrets/v0.1 Scout secret scan
sha256:d20496aab3d5e4b3a50e091bac7c0e7ddb1f6909c23e9ea0c0c3ae8e192abd31
Name │ dhi.io/python
digest │ d20496aab3d5
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://scout.docker.com/secrets/v0.1
https://scout.docker.com/tests/v0.1 Scout test report
sha256:7a2f5e93a4be1d0eb3c5ed966104c6fb193b87de3a20b7cb536bd10e4418daf2
Name │ dhi.io/python
digest │ 7a2f5e93a4be
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://scout.docker.com/tests/v0.1
https://scout.docker.com/virus/v0.1 Scout virus/malware report
sha256:55aa6a3cd931cfe60c4abff38787668580a1c425e6f385b6a8e9b04dd3a47931
Name │ dhi.io/python
digest │ 55aa6a3cd931
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://scout.docker.com/virus/v0.1
https://scout.docker.com/vulnerabilities/v0.1 Scout vulnerabilities
sha256:85ea5c8e021775fcd6933bfc712dd45b0ba63275e07b4bc44b1be440bf194a38
Name │ dhi.io/python
digest │ 85ea5c8e0217
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://scout.docker.com/vulnerabilities/v0.1
https://slsa.dev/provenance/v0.2 SLSA provenance
sha256:43283e5c83d2625542ee63797cf9cd3d0ee94e6012c6b5b8ed8c0a482e698156
Name │ dhi.io/python
digest │ 43283e5c83d2
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://slsa.dev/provenance/v0.2
https://slsa.dev/provenance/v1 SLSA provenance
sha256:22870de00ae3918dd426c22dff0628620586e50d97f14df52c846f266a232bb2
Name │ dhi.io/python
digest │ 22870de00ae3
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://slsa.dev/provenance/v1
https://slsa.dev/verification_summary/v1 SLSA verification summary
sha256:63485f84f89c1534b60e9a24b9bef9d4c10bba652bd9e351bb7861742b5a9c3c
Name │ dhi.io/python
digest │ 63485f84f89c
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://slsa.dev/verification_summary/v1
https://spdx.dev/Document SPDX SBOM
sha256:91c071b3faf69247626618fcf7cc758415553ab6edb394b50131cd50f3d36180
Name │ dhi.io/python
digest │ 91c071b3faf6
│
Media type │ application/vnd.oci.image.manifest.v1+json
Artifact type │ application/vnd.in-toto+json
Annotations │
in-toto.io/predicate-type │ https://spdx.dev/Document
➜ dhi-lab
You will see several attestations (SBOM, provenance, vulnerability reports, etc.).
Note: If the image is already present locally, prefix the name with
registry://:docker scout attest list registry://dhi.io/python:3.13
Step 2 — Retrieve and Verify an SBOM
docker scout attest get \
--predicate-type https://scout.docker.com/sbom/v0.1 \
--verify \
dhi.io/python:3.13
If verification succeeds you will see confirmation that the signature is valid, plus the equivalent cosign command.
You can also ask for a CycloneDX SBOM:
docker scout attest get \
--predicate-type https://cyclonedx.org/bom/v1.6 \
dhi.io/python:3.13
Or simply:
docker scout sbom dhi.io/python:3.13
Step 3 — Scan Your Own Application Image
Rebuild the small Flask app from Blog 2 (or any image you have):
pwd
#navigate to dhi-lab
dhi-lab # or recreate the simple app
docker build -t my-dhi-app:v1 .
➜ dhi-lab docker build -t my-dhi-app:v1 .
[+] Building 5.4s (19/19) FINISHED docker:desktop-linux
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 728B 0.0s
=> resolve image config for docker-image://docker.io/docker/dockerfile:1 1.7s
=> [auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:ecfaec9ed6d810b56388c508f4121597bfbba70d41a6dfeee4d8cad5f295fc32 0.0s
=> => resolve docker.io/docker/dockerfile:1@sha256:ecfaec9ed6d810b56388c508f4121597bfbba70d41a6dfeee4d8cad5f295fc32 0.0s
=> [internal] load metadata for dhi.io/python:3.13 2.2s
=> [internal] load metadata for dhi.io/python:3.13-dev 3.4s
=> [auth] python:pull token for dhi.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [builder 1/5] FROM dhi.io/python:3.13-dev@sha256:b31351cce7a96e52c272b009d9167f62e8ffba0f0531bce7c55b74d580c4363a 0.0s
=> => resolve dhi.io/python:3.13-dev@sha256:b31351cce7a96e52c272b009d9167f62e8ffba0f0531bce7c55b74d580c4363a 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 63B 0.0s
=> [stage-1 1/4] FROM dhi.io/python:3.13@sha256:5669b3baeccdcd7b189df90aab1616a92bee6a766dc537b90a169268c0ab962c 0.0s
=> => resolve dhi.io/python:3.13@sha256:5669b3baeccdcd7b189df90aab1616a92bee6a766dc537b90a169268c0ab962c 0.0s
=> CACHED [stage-1 2/4] WORKDIR /app 0.0s
=> CACHED [builder 2/5] WORKDIR /app 0.0s
=> CACHED [builder 3/5] RUN python -m venv /app/venv 0.0s
=> CACHED [builder 4/5] COPY requirements.txt . 0.0s
=> CACHED [builder 5/5] RUN pip install --no-cache-dir -r requirements.txt 0.0s
=> CACHED [stage-1 3/4] COPY --from=builder /app/venv /app/venv 0.0s
=> CACHED [stage-1 4/4] COPY app.py . 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => exporting manifest sha256:2d981cdcc89cc5122fae8386ac9291917ec2a6e1c3b0352025185161a8ab6e68 0.0s
=> => exporting config sha256:e9b998ce0fe58f26568f8371b1acfadeb88b6fdb621ef737cc3860e2ab98c1d2 0.0s
=> => exporting attestation manifest sha256:31ed97bd0834de4b09ba5d46c4245e340119ad852f6a4ee702c537cbfdc87ff6 0.0s
=> => exporting manifest list sha256:e8c9377134bb24982fd0fb771881c290c9a3545ba0177b0fb5041db927991aa3 0.0s
=> => naming to docker.io/library/my-dhi-app:v1 0.0s
=> => unpacking to docker.io/library/my-dhi-app:v1 0.0s
View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/pu3qzidtva9nrroqyhv7mlsm5
➜ dhi-lab
Scan it:
docker scout cves my-dhi-app:v1
Output
➜ dhi-lab docker scout cves my-dhi-app:v1
i New version 1.24.0 available (installed version is 1.23.1) at https://github.com/docker/scout-cli
✓ Image stored for indexing
✓ Indexed 107 packages
✓ Provenance obtained from attestation
✗ Detected 8 vulnerable packages with a total of 17 vulnerabilities
## Overview
│ Analyzed Image
───────────────────┼─────────────────────────────
Target │ my-dhi-app:v1
digest │ e8c9377134bb
platform │ linux/arm64
vulnerabilities │ 0C 3H 2M 12L
size │ 31 MB
packages │ 107
## Packages and Vulnerabilities
0C 2H 0M 0L msgpack 1.1.2
pkg:pypi/msgpack@1.1.2
✗ HIGH GHSA-6v7p-g79w-8964 [Use After Free]
https://scout.docker.com/v/GHSA-6v7p-g79w-8964
Affected range : <=1.2.0
Fixed version : 1.2.1
CVSS Score : 7.5
CVSS Vector : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
✗ HIGH CVE-2026-57585
https://scout.docker.com/v/CVE-2026-57585
Affected range : <1.2.1
Fixed version : 1.2.1
CVSS Score : 7.5
CVSS Vector : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
0C 1H 1M 0L setuptools 70.3.0
pkg:pypi/setuptools@70.3.0
✗ HIGH CVE-2025-47273 [Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')]
https://scout.docker.com/v/CVE-2025-47273
Affected range : <78.1.1
Fixed version : 78.1.1
CVSS Score : 7.7
CVSS Vector : CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P
✗ MEDIUM CVE-2026-59890 [Improper Handling of Unicode Encoding]
https://scout.docker.com/v/CVE-2026-59890
Affected range : <83.0.0
Fixed version : 83.0.0
CVSS Score : 6.1
CVSS Vector : CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N
0C 0H 1M 0L expat 2.8.2-1~deb13u1+dhi0
pkg:deb/debian/expat@2.8.2-1~deb13u1%2Bdhi0?os_distro=trixie&os_name=debian&os_version=13
✗ MEDIUM CVE-2026-72522
https://scout.docker.com/v/CVE-2026-72522
Affected range : >0
Fixed version : not fixed
0C 0H 0M 7L glibc 2.41-12+deb13u3+dhi1
pkg:deb/debian/glibc@2.41-12%2Bdeb13u3%2Bdhi1?os_distro=trixie&os_name=debian&os_version=13
✗ LOW CVE-2019-9192
https://scout.docker.com/v/CVE-2019-9192
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2019-1010025
https://scout.docker.com/v/CVE-2019-1010025
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2019-1010024
https://scout.docker.com/v/CVE-2019-1010024
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2019-1010023
https://scout.docker.com/v/CVE-2019-1010023
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2019-1010022
https://scout.docker.com/v/CVE-2019-1010022
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2018-20796
https://scout.docker.com/v/CVE-2018-20796
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2010-4756
https://scout.docker.com/v/CVE-2010-4756
Affected range : >0
Fixed version : not fixed
0C 0H 0M 2L sqlite3 3.46.1-7+deb13u1+dhi2
pkg:deb/debian/sqlite3@3.46.1-7%2Bdeb13u1%2Bdhi2?os_distro=trixie&os_name=debian&os_version=13
✗ LOW CVE-2025-70873
https://scout.docker.com/v/CVE-2025-70873
Affected range : >0
Fixed version : not fixed
✗ LOW CVE-2021-45346
https://scout.docker.com/v/CVE-2021-45346
Affected range : >0
Fixed version : not fixed
0C 0H 0M 1L openssl 3.5.6-1~deb13u2+dhi1
pkg:deb/debian/openssl@3.5.6-1~deb13u2%2Bdhi1?os_distro=trixie&os_name=debian&os_version=13
✗ LOW CVE-2010-0928
https://scout.docker.com/v/CVE-2010-0928
Affected range : >=3.2.1-3
Fixed version : not fixed
0C 0H 0M 1L flask 3.0.3
pkg:pypi/flask@3.0.3
✗ LOW CVE-2026-27205 [Use of Cache Containing Sensitive Information]
https://scout.docker.com/v/CVE-2026-27205
Affected range : <3.1.3
Fixed version : 3.1.3
CVSS Score : 2.3
CVSS Vector : CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N
0C 0H 0M 1L util-linux 2.41.5-0+deb13u1+dhi2
pkg:deb/debian/util-linux@2.41.5-0%2Bdeb13u1%2Bdhi2?os_distro=trixie&os_name=debian&os_version=13
✗ LOW CVE-2022-0563
https://scout.docker.com/v/CVE-2022-0563
Affected range : >0
Fixed version : not fixed
17 vulnerabilities found in 8 packages
CRITICAL 0
HIGH 3
MEDIUM 2
LOW 12
What's next:
View base image update recommendations → docker scout recommendations my-dhi-app:v1
➜ dhi-lab
Compare with the pure base:
docker scout compare my-dhi-app:v1 --to dhi.io/python:3.13 --ignore-unchanged
Output
➜ dhi-lab docker scout compare my-dhi-app:v1 --to dhi.io/python:3.13 --ignore-unchanged
i New version 1.24.0 available (installed version is 1.23.1) at https://github.com/docker/scout-cli
! 'docker scout compare' is experimental and its behaviour might change in the future
✓ Image stored for indexing
✓ Indexed 107 packages
✓ Provenance obtained from attestation
✓ SBOM obtained from attestation, 100 packages found
✓ Provenance obtained from attestation
✓ Policy evaluation completed
✓ VEX statements obtained from attestation
✓ Policy evaluation completed
✓ VEX statements obtained from attestation
## Overview
│ Analyzed Image │ Comparison Image
───────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────
Target │ my-dhi-app:v1 │ dhi.io/python:3.13
digest │ e8c9377134bb │ 24a8822f76af
tag │ v1 │ 3.13
platform │ linux/arm64 │ linux/arm64
provenance │ │ https://github.com/docker-hardened-images/definitions
│ │ 5fb32dbb43253700792f258345f151035442841c
vulnerabilities │ 0C 3H 2M 12L │ 0C 0H 1M 0L
│ +3 +1 +12 │
size │ 31 MB (+5.4 MB) │ 26 MB
packages │ 107 (+7) │ 100
│ │
## Environment Variables
- PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+ PATH=/app/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+ PYTHONDONTWRITEBYTECODE=1
+ PYTHONUNBUFFERED=1
PYTHON_VERSION=3.13.15
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
## Labels
com.docker.dhi.chain-id=sha256:a12342a94f7cf5f1d5dc0c6bc57007908b47f8e8681d261c97ec9aa60c9cdcc0
com.docker.dhi.compliance=cis
com.docker.dhi.created=2026-08-12T13:14:57Z
com.docker.dhi.date.end-of-life=2029-10-31
com.docker.dhi.date.release=2024-10-07
com.docker.dhi.definition=image/python/debian-13/3.13
com.docker.dhi.distro=debian-13
com.docker.dhi.entitlement=public
com.docker.dhi.flavor=
com.docker.dhi.name=dhi/python
com.docker.dhi.package-manager=
com.docker.dhi.shell=
com.docker.dhi.title=Python 3.13.x
com.docker.dhi.url=https://dhi.io/catalog/python
com.docker.dhi.variant=runtime
com.docker.dhi.version=3.13.15-debian13
## Config
+ 8000/tcp=
- cmd=python3
+ cmd=python app.py
user=65532
- workdir=/
+ workdir=/app
## Policies
0 improved, 2 worsened
Policy Analyzed Comparison Change
Default non-root user ✓ ✓ No Change
No copyleft licenses ! 119 ! 119 No Change
No fixable critical or high vulnerabilities ! 3 ✓ +3 Worsened
No high-profile vulnerabilities ✓ ✓ No Change
No outdated base images ✓ ✓ No Change
No unapproved base images ✓ ✓ No Change
Supply chain attestations ! 1 ✓ +1 Worsened
View policy details → docker scout policy my-dhi-app:v1
## Packages and Vulnerabilities
+ 7 packages added
95 packages unchanged
+ 16 vulnerabilities added
Package Type Version Compared Version
+ blinker pypi 1.9.0
+ click pypi 8.4.2
+ flask pypi 3.0.3
└─ + LOW CVE-2026-27205 [https://scout.docker.com/v/CVE-2026-27205]
2.3 Use of Cache Containing Sensitive Information
✓ fixed in 3.1.3
+ itsdangerous pypi 2.2.0
+ jinja2 pypi 3.1.6
+ markupsafe pypi 3.0.3
+ werkzeug pypi 3.1.8
➜ dhi-lab
Step 4 — Evaluate Against Official DHI Policies
Docker publishes the exact policy set that hardened images are held to. You can apply the same policies to any image:
docker scout policy my-dhi-app:v1 --policy-bundle dhi/policies:latest
Output
➜ dhi-lab docker scout policy my-dhi-app:v1 --policy-bundle dhi/policies:latest
i New version 1.24.0 available (installed version is 1.23.1) at https://github.com/docker/scout-cli
! 'docker scout policy' is experimental and its behaviour might change in the future
✓ Image stored for indexing
✓ Indexed 107 packages
✓ Provenance obtained from attestation
✓ Policy evaluation completed
## Overview
│ Analyzed Image
────────────┼─────────────────
Target │ my-dhi-app:v1
digest │ e8c9377134bb
platform │ linux/arm64
## Policies
Policy status FAILED (4/9 policies met)
Status │ Policy │ Results
────────┼───────────────────────────────────────────────┼─────────────────────────────
✓ │ No default root user for non-dev images │
! │ Image contains embedded malware │ 2 deviations
! │ Image contains embedded secrets │ 2 deviations
! │ Image has failing tests │ 2 deviations
! │ Fixable vulnerabilities past remediation SLA │ 0C 3H 0M 1L
✓ │ No high-profile vulnerabilities │ 0C 0H 0M 0L
✓ │ STIG scan │ 0 deviations
! │ Missing or unsigned supply chain attestations │ 6 deviations
✓ │ Unintentional shell or package manager │ 0 deviations
## "No embedded malware" policy evaluation results
This policy checks that no malware is embedded in the image.
Predicate │ Reason
─────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────
https://scout.docker.com/virus/v0.1 │ doesn't match subject sha256:e8c9377134bb24982fd0fb771881c290c9a3545ba0177b0fb5041db927991aa3
https://scout.docker.com/virus/v0.1 │ is missing
## "No embedded secrets" policy evaluation results
This policy checks that no secrets are embedded in the image.
Predicate │ Reason
───────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────
https://scout.docker.com/secrets/v0.1 │ doesn't match subject sha256:e8c9377134bb24982fd0fb771881c290c9a3545ba0177b0fb5041db927991aa3
https://scout.docker.com/secrets/v0.1 │ is missing
## "No failing tests" policy evaluation results
This policy checks that the image has tests and none are failing.
Predicate │ Reason
─────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────
https://scout.docker.com/tests/v0.1 │ doesn't match subject sha256:e8c9377134bb24982fd0fb771881c290c9a3545ba0177b0fb5041db927991aa3
https://scout.docker.com/tests/v0.1 │ is missing
## "No fixable vulnerabilities past their remediation SLA" policy evaluation results
Flags packages with a fixable CVE whose remediation SLA has elapsed. SLAs vary by severity, with a shorter SLA for CISA KEV-listed vulnerabilities. Only vulnerabilities that have a fix available are considered.
Vulnerability │ Severity │ Current package version │ Fix version
─────────────────────┼────────────┼────────────────────────────┼─────────────
CVE-2026-57585 │ HIGH │ pkg:pypi/msgpack@1.1.2 │ 1.2.1
GHSA-6v7p-g79w-8964 │ HIGH │ pkg:pypi/msgpack@1.1.2 │ 1.2.1
CVE-2025-47273 │ HIGH │ pkg:pypi/setuptools@70.3.0 │ 78.1.1
CVE-2026-27205 │ LOW │ pkg:pypi/flask@3.0.3 │ 3.1.3
## "Signed supply chain attestations" policy evaluation results
This policy checks that all required SSC attestations are available and signed by a trusted party.
Predicate │ Reason
──────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────
https://slsa.dev/provenance/v0.2 │ doesn't match subject sha256:e8c9377134bb24982fd0fb771881c290c9a3545ba0177b0fb5041db927991aa3
https://slsa.dev/provenance/v0.2 │ doesn't resolve to image ref
https://slsa.dev/provenance/v0.2 │ is missing
https://spdx.dev/Document │ doesn't match subject sha256:e8c9377134bb24982fd0fb771881c290c9a3545ba0177b0fb5041db927991aa3
https://spdx.dev/Document │ doesn't resolve to image ref
https://spdx.dev/Document │ is missing
What's next:
View vulnerabilities → docker scout cves my-dhi-app:v1
View base image update recommendations → docker scout recommendations my-dhi-app:v1
Compare with the latest in the registry → docker scout compare --to-latest my-dhi-app:v1
➜ dhi-lab
bash
The command pulls the policy bundle, generates an SBOM for your image, enriches it with CVE/VEX data, and checks every policy.
Typical policies in the bundle include:
- Runs as non-root (for non-dev images)
- No fixable critical/high CVEs past the remediation window
- No high-profile / known-exploited vulnerabilities
- No embedded malware or secrets
- Signed supply-chain attestations present
- No unintentional shell or package manager
Policy Evaluation Flow
Explanation
Scout does not just look at the base image. It analyses the full contents of your image and tells you whether it meets the same bar that Docker Hardened Images are required to meet.
Step 5 — Fix a Failing Check (Hands-on)
If the policy run reports that your image runs as root or contains an unexpected shell, go back to the multi-stage Dockerfile from Blog 2 and ensure:
- Final stage uses a pure runtime variant (not
-dev) - You did not accidentally add a shell or switch to
USER root
Rebuild and re-run the policy command until it is clean.
Let’s Break It
- Build a naïve image that starts from a normal
python:3.13and runs as root. - Run
docker scout policy ... --policy-bundle dhi/policies:latest. - Observe the failures (root user, extra packages, missing attestations, etc.).
- Switch the base to a DHI runtime image and rebuild — most failures disappear.
Production Thinking
In a real pipeline I would:
- Always verify DHI attestations when pulling base images in CI
- Run
docker scout policy --policy-bundle dhi/policies:latestas a required gate - Fail the build if critical policies are not met
- Keep the policy config in the repository so the whole team uses the same rules
- Prefer images that already carry signed SBOMs and provenance
Security Considerations
- A signed SBOM tells you what is inside; it does not magically remove vulnerabilities
- VEX helps you ignore CVEs that are not exploitable in this particular image
- Provenance proves the build process; it does not prove the application code is correct
- Policy evaluation is only as good as the policies you enable
Common Mistakes
- Forgetting the
registry://prefix when the image is already local - Expecting every attestation type on every variant (some are variant-specific)
- Treating a green Scout report as “the application is secure”
- Not pinning the policy-bundle digest in CI (using
:latestis convenient but less reproducible)
Troubleshooting
| Problem | Check / Command | Fix |
|---|---|---|
unauthorized on attest list |
docker login dhi.io |
Re-authenticate |
| Attestation not found | Image name / tag / platform | Use exact tag and --platform if needed |
| Signature verification fails | Network / key | Try --skip-tlog if transparency log issue |
| Policy bundle pull fails | Docker Hub login |
docker login (normal Hub credentials) |
| Too many policy failures | Base image still official | Switch final stage to a DHI runtime variant |
Cleanup
docker rmi my-dhi-app:v1 2>/dev/null || true
What We Learned
- Every DHI carries signed SBOMs, provenance and other attestations
- You can list, retrieve and cryptographically verify them with Docker Scout
- The same policy bar that Docker applies to hardened images can be applied to your own images
- This gives real supply-chain transparency, not just marketing claims
You can now prove what is inside an image and enforce the same standards yourself.
What’s Next?
In Blog 4 we put everything into practice for CI/CD: proper multi-stage Dockerfiles, caching, authenticating to dhi.io in pipelines, and making the DHI policy check a required gate so every build stays clean.
References
- https://docs.docker.com/dhi/how-to/verify/ — listing and verifying attestations
- https://docs.docker.com/dhi/how-to/policies/ — DHI policy bundle
- https://docs.docker.com/dhi/core-concepts/ — SBOM, SLSA, provenance, signatures
- https://docs.docker.com/dhi/core-concepts/sbom/ — SBOM details
- https://docs.docker.com/dhi/core-concepts/signatures/ — code signing
All commands and behaviour verified against current official documentation (August 2026).


Top comments (0)