Annotations have been part of the Open Container Initiative (OCI) specification since version 1.0.0 dating back to 2017. However, their more extensive use saw uptick only recently – mainly with the proliferation of certified and hardened images and the increased need for supply chain security and vulnerability management. OCI annotations allow you to enrich the container images with useful metadata that travels with the image itself and can enable advanced security and vulnerability management scenarios. Here are two very common scenarios that I hear from customers regularly.
Security Scenarios OCI Annotations Enable
The first scenario is related to runtime vulnerability scanners. Normally scanners scan the inventory on the runtime nodes and identify the images by their sha256 digest and not by their user-friendly tag. The vulnerability reporting in the security tools reports the digest to users, which adds confusion and increases the toil of figuring out what image needs to be updated and redeployed. Even advanced scanners need to keep a database mapping the tags to the digests separately and cross-reference that database when reporting, which increases the cost of implementation and running the vulnerability scanning and reporting system.
Another common scenarios that customers report is the need to identify the “owner” of the image that is reported by the vulnerability scanner. This is needed to track down the team or the vendor that needs to remediate the vulnerabilities and rebuild the image with the fixes.
There are others but those are the ones I’ve heard from customers again and again over the years.
Current State of Use of OCI Annotations
I did a quick check with the most common registries used by the industry today to see whether images present in those registries use OCI annotations – standard or custom. This is by no means an extensive research but just a gut check what is available in the industry.
The easiest way to check is to use oras (or other similar tool like crane, regctl, or even my own regshape) to pull the image manifest and look for annotations property. The two commands that will work are:
oras manifest fetch [image] | jq -r '.manifests[].annotations' for manifest index, and
oras manifest fetch [image] | jq -r '.annotations' for individual image manifests.
Here are the results of my quick litmus test pulling the Python image from various registries. All runs are done at the day of this post. I will elaborate on the annotations later on.
Docker Hub Library Images
Docker Hub library images are still the most commonly used images in the industry. Here is the result for the python:3.13 image.
~ oras manifest fetch docker.io/library/python:3.13 | jq -r '.manifests[0].annotations'
{
"com.docker.official-images.bashbrew.arch": "amd64",
"org.opencontainers.image.base.digest": "sha256:cbe2f66893063158a5554ba5583c5b508ed614a21688fe1afcd5946b5eaadf7e",
"org.opencontainers.image.base.name": "buildpack-deps:trixie",
"org.opencontainers.image.created": "2026-06-24T04:46:20Z",
"org.opencontainers.image.revision": "f79aea5b8f6b2d65b31ba2bb3f69c0c2083345c8",
"org.opencontainers.image.source": "https://github.com/docker-library/python.git#f79aea5b8f6b2d65b31ba2bb3f69c0c2083345c8:3.13/trixie",
"org.opencontainers.image.url": "https://hub.docker.com/_/python",
"org.opencontainers.image.version": "3.13.14-trixie"
}
Amazon ECR Public Gallery Images
Python python:trixie image in ECR Public Gallery is a one-to-one copy of the Docker Hub image and has exactly the same annotations:
~ oras manifest fetch public.ecr.aws/docker/library/python:trixie | jq -r '.manifests[0].annotations'
{
"com.docker.official-images.bashbrew.arch": "amd64",
"org.opencontainers.image.base.digest": "sha256:cbe2f66893063158a5554ba5583c5b508ed614a21688fe1afcd5946b5eaadf7e",
"org.opencontainers.image.base.name": "buildpack-deps:trixie",
"org.opencontainers.image.created": "2026-06-24T04:45:11Z",
"org.opencontainers.image.revision": "7914d06b7ddb34b99975318016ab5b9c18264015",
"org.opencontainers.image.source": "https://github.com/docker-library/python.git#7914d06b7ddb34b99975318016ab5b9c18264015:3.14/trixie",
"org.opencontainers.image.url": "https://hub.docker.com/_/python",
"org.opencontainers.image.version": "3.14.6-trixie"
}
Google Distroless Images
Google produces distroless images that are considered more secure because they contain less vulnerabilities. However, Google distroless images are not enriched with any OCI annotations. The output of the command returns no annotations on both the manifest index and the individual image manifests.
~ oras manifest fetch gcr.io/distroless/python3:latest | jq -r '.manifests[0].annotations' null ~ oras manifest fetch gcr.io/distroless/python3@sha256:e9af9ebe3e56417dd852ef7253b4d1d846783b21adda977bc362993e322a686d | jq -r '.annotations' null
RedHat Container Registry Images
Python python-312:9.8-1782966301 image in RedHat’s container registry is not enriched with OCI annotations. Interestingly, if you explore the manifest of that image, you will even see that it is not in OCI format but the legacy Docker manifest format. Here the results:
~ oras manifest fetch registry.access.redhat.com/ubi9/python-312:9.8-1782966301 | jq -r '.manifests[0].annotations' null ~ oras manifest fetch registry.access.redhat.com/ubi9/python-312:9.8-1782966301 | jq -r '.annotations' null
NVIDIA NGC Container Registry Images
NVIDIA also does not enrich images with OCI annotations. Here are the results for the CUDA Python image python-cuda129:1.0.2:
~ oras manifest fetch nvcr.io/nvidia/ai-workbench/python-cuda129:1.0.2 | jq -r '.manifests[0].annotations' null ~ oras manifest fetch nvcr.io/nvidia/ai-workbench/python-cuda129:1.0.2 | jq -r '.annotations' null
Microsoft Artifact Registry Images
Microsoft Artifact Registry (MAR) is the official distribution vehicle for container images built by Microsoft. The Python image there is Azure Linux based but it is not enriched with OCI annotations. Here the results for python:3:
~ oras manifest fetch mcr.microsoft.com/azurelinux/base/python:3 | jq -r '.manifests[0].annotations' null ~ oras manifest fetch mcr.microsoft.com/azurelinux/base/python:3 | jq -r '.annotations' null
The picture looks a little bit differently when it comes to certified images. You should expect that certified and hardened images are built with more metadata and attestations.
Chainguard Container Registry Images
As expected Chainguard certified images do have useful annotations in addition to the other supply chain attestations like SBOMs and SLSA provenance. Here is the result for python:latest image:
~ oras manifest fetch cgr.dev/chainguard/python:latest | jq -r '.annotations'
{
"dev.chainguard.image.title": "python",
"dev.chainguard.package.main": "",
"org.opencontainers.image.authors": "Chainguard Team https://www.chainguard.dev/",
"org.opencontainers.image.created": "2026-06-30T09:49:39Z",
"org.opencontainers.image.source": "https://github.com/chainguard-images/images/tree/main/images/python",
"org.opencontainers.image.title": "python",
"org.opencontainers.image.url": "https://images.chainguard.dev/directory/image/python/overview",
"org.opencontainers.image.vendor": "Chainguard"
}
Docker Hardened Images (DHI)
DHI images have the even more extensive list of annotations than the public Docker Hub ones. Here the list for python:3.13:
~ oras manifest fetch dhi.io/python:3.13 | jq -r '.annotations'
{
"com.docker.dhi.chain-id": "sha256:17ecf3c1e662d09d6a305c49ae2b014156442cd7988da530e3976c13abe06968",
"com.docker.dhi.compliance": "cis",
"com.docker.dhi.created": "2026-07-02T23:13:36Z",
"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.14-debian13",
"org.opencontainers.image.authors": "Docker, Inc. https://docker.com",
"org.opencontainers.image.created": "2026-07-02T23:37:14Z",
"org.opencontainers.image.description": "A minimal Python image / Python 3.13.x",
"org.opencontainers.image.documentation": "https://dhi.io/catalog/python/guides",
"org.opencontainers.image.licenses": "PSF-2.0",
"org.opencontainers.image.revision": "3e8c5821653b13c1d7da10305bc3eae0f3b8fbba",
"org.opencontainers.image.source": "https://github.com/docker-hardened-images/definitions",
"org.opencontainers.image.title": "dhi/python",
"org.opencontainers.image.url": "https://dhi.io/catalog/python",
"org.opencontainers.image.vendor": "Docker, Inc.",
"org.opencontainers.image.version": "3.13.14-debian13"
}
Minimus Hardened Container Images
Minimus is another vendor that offers hardened images. Their annotations are more limited. Here the result for the python:3.14 image:
~ oras manifest fetch reg.mini.dev/python:3.14 | jq -r '.annotations'
{
"io.minimus.images.line": "3.14",
"org.opencontainers.image.created": "2026-06-28T13:33:58Z",
"org.opencontainers.image.url": "https://images.minimus.io/gallery/images/python",
"org.opencontainers.image.version": "3.14.6"
}
RedHat Hardened Images
Surprisingly RedHat Hardened Images do not have annotations. Unlike the public RedHat images, though, they are in OCI format. Here the result for python:3:
~ oras manifest fetch registry.access.redhat.com/hi/python:3 | jq -r '.manifests[0].annotations' null ~ oras manifest fetch registry.access.redhat.com/hi/python:3 | jq -r '.annotations' null
How to Use OCI Annotations for Security Purposes?
As of today, I have implemented the following list of annotations for my example CSSC framework project:
~ oras manifest fetch ghcr.io/toddysm/apps/cssc-dashboard/dashboard-web:0.1.2 | jq -r '.annotations'
{
"com.toddysm.build.run-url": "https://github.com/toddysm/cssc-framework/actions/runs/28605848406",
"com.toddysm.build.workflow": "build / cssc-dashboard",
"com.toddysm.image.base.tag": "3.14-slim",
"com.toddysm.image.lineage": "0.1",
"com.toddysm.image.tags": "0|0.1|0.1.2|0.1.2-32cf0a0",
"com.toddysm.security.policy": "https://github.com/toddysm/cssc-framework?tab=security-ov-file",
"com.toddysm.security.report-url": "https://github.com/toddysm/cssc-framework/security/advisories/new",
"org.opencontainers.image.base.digest": "sha256:b877e50bd90de10af8d82c57a022fc2e0dc731c5320d762a27986facfc3355c1",
"org.opencontainers.image.base.name": "ghcr.io/toddysm/golden/python",
"org.opencontainers.image.created": "2026-07-02T16:31:48Z",
"org.opencontainers.image.description": "CSSC Dashboard web UI and stage registry (BFF)",
"org.opencontainers.image.documentation": "https://github.com/toddysm/cssc-framework/blob/main/docs/architecture/run/cssc-dashboard.md",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.revision": "32cf0a0d171c5bac41d0dbced516e8cf22794990",
"org.opencontainers.image.source": "https://github.com/toddysm/cssc-framework",
"org.opencontainers.image.title": "dashboard-web",
"org.opencontainers.image.url": "https://github.com/toddysm/cssc-framework",
"org.opencontainers.image.vendor": "toddysm.com",
"org.opencontainers.image.version": "0.1.2-32cf0a0"
}
Here is how you can use some of those annotations for supply chain security and vulnerability management purposes.
Use Annotations to Manage Vulnerabilities
The org.opencontainers.image.version contains the immutable tag used to tag the image at build time. Tag information is now built into the image manifest itself and can be carried together with the image. Even if the tag is overwritten in the registry, pulling the image manifest will always tell you what tag the image was tagged with at build time. Referring to the first scenario that I mentioned above scanners don’t need to create separate mapping for keeping the SHA-to-tag information.
However, the image can be tagged with multiple tags at build time. The standard OCI annotation is not intended to store multiple tags. Hence, I added a custom annotation com.toddysm.image.tags that contains the full list of tags used to tag the image at build time. Combining this information with the standard OCI annotation org.opencontainers.image.created and the digest of the image allows you to easily determine if two digests are from the same family of images (Don’t forget that you can rename and retag the image as you want at any time and the name of the image is an unreliable way to compare two images).
The com.toddysm.image.lineage annotation brings that further. Knowing that two images are from the same lineage and using the org.opencontainers.image.created annotation, you can clearly determine the sequence of updates of images. Here is how you can leverage that information.
Your vulnerability scanner finds vulnerabilities in the image deployed to your Kubernetes cluster. You check the manifest of the image on the runtime cluster and find out that this image is from lineage 1.0 and it was created on 2026-06-05T16:31:48Z. You check in your registry and there is an image tagged with tag 1.0 that is created on 2026-07-02T16:31:48Z. (Note: the org.opencontainers.image.title annotation should contain the image repo and I just noticed a bug in my implementation.) The latter image is the latest from the lineage and it is assumed that it has the vulnerabilities patched. Also, because the major and the minor version are not changed (assuming you are following the rules of semantic versioining) it is safe to assume that there will be no breaking changes.
Track Dependencies Using Annotations
The standard OCI annotations org.opencontainers.image.base.name and org.opencontainers.image.base.digest uniquely identify the base image used to build your application image. Though, the usual problem with the digest is that it is not user friendly and registries do not offer digest to tag mapping and tag history out of the box. However, if you add a custom annotation as I the one I added above com.toddysm.image.base.tag and if all your base images are also annotated with the above set of annotations, you can automate the process of rebuilding the image with tools like Dependabot for example.
Here is how this may work. Your dependency tool checks the image manifest and sees that it is based on python:3.14-slim. It also checks the digest of the image. Then it checks the registry where the base image is sourced from and uses pulls the base image using the digest. Then it pulls the image with the python:3.14-slim tag. It compares the org.opencontainers.image.created date of both images. If the org.opencontainers.image.created date of the image pulled by tag is newer (which, theoretically, must be the case) the tool creates a PR for updating the application image.
Assign Security Action Items to the Correct Owners
One of the most common complains I hear from customers is that when they discover vulnerabilities in a container image they struggle to find the rightful owner to fix those vulnerabilities. Most of the times teams use images buld by other teams or open source and without any additional metadata it is hard to know where the image came from and who built it.
This is somewhat solved with the standard OCI annotations org.opencontainers.image.source, org.opencontainers.image.title, org.opencontainers.image.url, org.opencontainers.image.vendor. If set, those four annotations should be enough to clearly identify the owner of the image. Of course, you can also add custom annotations like the ones I added com.toddysm.build.run-url and com.toddysm.build.workflow but those and more should also be available in the SLSA provenance attestation if it is available for the image. However, if SLSA provenance is not available you can still instrument your builds to add the annotations and use them later on to properly assign any action items to the rightful owners.
Automate the Process of Vulnerability Filing
Finally, using annotations like com.toddysm.security.policy and com.toddysm.security.report-url can help you automate the process of filing security issues for the image owner. In my case, the reporting URL goes directly to the form to file security issues for the CSSC Framework GitHub project. You can also leverage AI agent to interpret the security policy and take the appropriate actions based on the information described there.
Guidelines
OCI annotations are powerful way to add metadata to your container images and cloud-native artifacts. Unfortunately they are underutilized and neglected. Developing good annotation practices in your organization can help you better manage the artifacts’ supply chain and vulnerabilities and meaningfully increase the security of your applications.
Here are some guidelines for you to improve your supply chain security and vulnerability management for container images.
- Always source your images, including base images, from a registry you have control and one that your tools can access.
- Migrate to OCI image format to leverage more advanced feature like annotations.
- Always set the standard OCI annotations at build.
- Implement custom annotations to aid your security and vulnerability management processes.
- Leverage annotations to provide richer reporting capabilities and automate the process for security and vulnerability management.
There are more things to do with annotations but I will cover more of them in subsequent posts.

Leave a Reply