DEV Community

Cover image for SBOM, Provenance, Signatures, Scanning & DHI Policies
Koti Vellanki
Koti Vellanki

Posted on

SBOM, Provenance, Signatures, Scanning & DHI Policies

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.io already 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

supply chain 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
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Or simply:

docker scout sbom dhi.io/python:3.13
Enter fullscreen mode Exit fullscreen mode

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 .
Enter fullscreen mode Exit fullscreen mode
➜  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 

Enter fullscreen mode Exit fullscreen mode

Scan it:

docker scout cves my-dhi-app:v1
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

Compare with the pure base:

docker scout compare my-dhi-app:v1 --to dhi.io/python:3.13 --ignore-unchanged
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 

Enter fullscreen mode Exit fullscreen mode


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

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

  1. Build a naïve image that starts from a normal python:3.13 and runs as root.
  2. Run docker scout policy ... --policy-bundle dhi/policies:latest.
  3. Observe the failures (root user, extra packages, missing attestations, etc.).
  4. 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:latest as 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 :latest is 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
Enter fullscreen mode Exit fullscreen mode

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

All commands and behaviour verified against current official documentation (August 2026).

Top comments (0)