Security Labels and Metadata
Hummingbird container images include labels, embedded metadata, and SBOMs that enable security scanners to perform container-first vulnerability reporting.
Overview
Security scanners need a way to determine which vulnerabilities are applicable to a container image. Three mechanisms provide this information:
- Container Labels - OCI image labels (
name,cpe) set in the Containerfile - Embedded Metadata - A
labels.jsonfile written to the container filesystem during build - Software Bill of Materials (SBOM) - An SPDX document listing all packages, attached as an OCI artifact alongside the image
Labels and embedded metadata identify the product; the SBOM identifies the packages within it. Labels and embedded metadata provide the same core information but serve different access paths: labels are accessible via container inspection tools, while embedded metadata is accessible to scanners with only filesystem access.
Applicability
The cpe label is only added to released Hummingbird distro images (no
CPE identifier for non-product images). All other labels are added to all
images.
The labels.json embedded metadata file contains all Containerfile LABEL
values plus auto-computed fields.
SBOMs are attached to all released images (both Rawhide and Hummingbird).
Container Labels
name
- Type: String
- Format:
<org>/<image>or<org>/<image>-<variant> - Examples:
hummingbird/nodejs-24,hummingbird/nodejs-24-builder,hummingbird/caddy - Description: Canonical name for the container image. This is the name that appears in VEX (Vulnerability Exploitability eXchange) statements and is used by scanners to map vulnerabilities to specific images.
The canonical name is derived from the image directory name (which includes
the version, e.g. nodejs-24) and the variant. For default variants, the
name is hummingbird/<image> (e.g. hummingbird/nodejs-24). For non-default
variants, the variant is appended with a hyphen (e.g.
hummingbird/nodejs-24-builder). Note that the canonical name may differ
from the registry repository path. For example, nodejs-24 and nodejs-20
are both pushed to the hummingbird/nodejs registry repository with
different tags, but their canonical names are hummingbird/nodejs-24 and
hummingbird/nodejs-20 respectively.
See container-image-labels.md for the full
name label format across all image types.
cpe
- Type: String (CPE 2.2 formatted)
- Format:
cpe:/a:redhat:hummingbird:1 - Description: Common Platform Enumeration (CPE) identifier for the container. CPE is a standardized naming scheme for software products that enables correlation with vulnerability databases.
The CPE value is defined globally in images/variables.yml and applied to all
Hummingbird images. Containers with the same CPE are considered the same
software product for vulnerability reporting purposes.
org.opencontainers.image.created
- Type: String (RFC3339 timestamp)
- Format:
2025-01-15T12:00:00Z - Description: Creation timestamp of the container image. Used by scanners to determine if an image predates or postdates a vulnerability fix.
If SOURCE_DATE_EPOCH is set during the build, that timestamp is used instead
of the actual build time, supporting reproducible builds.
Embedded Metadata (labels.json)
The labels.json file is written to /usr/share/buildinfo/labels.json inside
the container filesystem by the inject-source-info script during build. It
contains all Containerfile LABEL values plus auto-computed fields like
architecture and org.opencontainers.image.created.
Schema
The file follows the embedded_metadata.v1 schema published by Red Hat Product Security.
Fields
The embedded_metadata.v1 schema defines the minimum fields required by security scanners:
| Field | Type | Description |
|---|---|---|
name |
string | Canonical container name (e.g., hummingbird/nodejs-24) |
cpe |
string | CPE identifier (e.g., cpe:/a:redhat:hummingbird:1) |
architecture |
string | Target architecture (e.g., amd64, arm64) |
org.opencontainers.image.created |
string | RFC3339 creation timestamp |
The file also includes all other Containerfile LABEL values (e.g.,
description, summary, vendor, version). See
container-image-labels.md for the complete
label reference.
Example
{
"name": "hummingbird/caddy",
"cpe": "cpe:/a:redhat:hummingbird:1",
"architecture": "amd64",
"org.opencontainers.image.created": "2025-01-15T12:00:00Z"
}
Software Bill of Materials (SBOM)
Each released image has a per-architecture SPDX 2.3 SBOM attached as an OCI artifact. See SBOM Generation for how the production SBOMs are built from Syft, Hermeto, and Mobster.
Accessing SBOMs
SBOMs are stored as OCI artifacts alongside each per-architecture image. To download one, resolve the per-arch digest and use cosign:
IMAGE="quay.io/hummingbird/caddy"
TAG="latest"
ARCH="amd64"
# Get per-architecture digests from the image index
skopeo inspect --raw "docker://${IMAGE}:${TAG}" \
| jq '.manifests[] | {digest, platform}'
# Download the SBOM for the chosen architecture
ARCH_DIGEST="$(skopeo inspect --raw "docker://${IMAGE}:${TAG}" \
| jq -r --arg arch "${ARCH}" \
'.manifests[] | select(.platform.architecture == $arch) | .digest')"
cosign download sbom "${IMAGE}@${ARCH_DIGEST}" > sbom.json
Entry Sources
The merged SBOM contains entries from two tools:
| Source | Content | Scope |
|---|---|---|
| Syft | Installed binary RPMs + non-RPM packages | Image architecture only |
| Hermeto | Build-time dependencies from lockfiles | All architectures + source RPMs |
A package installed in the final image may have entries from both Syft and Hermeto (with different metadata), since it was both a build dependency and is present at runtime.
Distinguishing Entry Sources
After the Mobster merge, Syft and Hermeto entries carry mutually exclusive markers:
| Marker | Syft | Hermeto |
|---|---|---|
sourceInfo field present |
✓ | |
licenseDeclared set |
✓ | |
| CPE references | ✓ | |
upstream= in PURL |
✓ | |
| Annotation containing “hermeto” | ✓ | |
repository_id= in PURL |
✓ |
As a general rule, any entry with an annotation containing the word “hermeto” (case-insensitive) originates from Hermeto (build-time provenance). All other entries originate from Syft (runtime image scan).
PURL Format
Syft and Hermeto use different PURL qualifier sets for the same package. Examples from caddy:latest (Hummingbird, amd64):
Syft (runtime):
pkg:rpm/hummingbird/caddy@2.10.2-1.hum1?arch=x86_64&distro=hummingbird-20251124&upstream=caddy-2.10.2-1.hum1.src.rpm
Hermeto (build, binary):
pkg:rpm/caddy@2.10.2-1.hum1?arch=x86_64&checksum=sha256:ca02a0...&repository_id=public-hummingbird-x86_64-rpms
Hermeto (build, source):
pkg:rpm/caddy@2.10.2-1.hum1?arch=src&checksum=sha256:42912d...&repository_id=public-hummingbird-source-rpms
Key differences:
- Distro namespace: Syft includes the distro in the PURL path
(
pkg:rpm/hummingbird/...). Hermeto omits it (pkg:rpm/...). - EVR: Syft populates
versionInfowith the full epoch:version-release. Hermeto setsversionInfoto the bare upstream version; the full EVR is only in the PURL@version. - Architecture: Syft entries match the image architecture. Hermeto entries
carry an
arch=PURL qualifier that may be the image arch, a different arch (cross-arch),noarch, orsrc(source RPMs). - Source RPM: Syft entries carry
upstream=<srpm>in the PURL. Hermeto entries have separatearch=srcentries instead.
Hermeto Annotation Format
Hermeto entries carry annotations with JSON-encoded metadata:
{
"annotationDate": "2026-03-02T11:58:12Z",
"annotationType": "OTHER",
"annotator": "Tool: hermeto:jsonencoded",
"comment": "{\"name\": \"hermeto:found_by\", \"value\": \"hermeto\"}"
}
Entry Breakdown Example
Typical counts for caddy:latest (Hummingbird, amd64); exact counts vary as image dependencies change:
| Source | Typical count | Content |
|---|---|---|
| Syft | ~53 | Binary RPMs (x86_64 + noarch) |
| Syft | 1 | Go module (stdlib) |
| Syft | 2 | OCI image metadata |
| Hermeto | ~41 | Binary RPMs (x86_64) |
| Hermeto | ~41 | Binary RPMs (aarch64, cross-arch) |
| Hermeto | ~11 | Binary RPMs (noarch) |
| Hermeto | ~36 | Source RPMs (arch=src) |
How Scanners Use This Metadata
- CPE Matching: Scanners use the
cpevalue to look up applicable VEX statements for the product - Name Matching: The
nameidentifies which specific container the VEX statements apply to - Version Comparison: The creation timestamp enables comparison between the scanned image and fixed versions reported in VEX statements
- Package Enumeration: Scanners use the SBOM to enumerate all packages in the image and correlate them with vulnerability databases via PURLs and CPEs
Related Files
| File | Purpose |
|---|---|
documentation/background/container-image-labels.md |
Complete reference for all image labels |
documentation/background/image-pipeline.md |
SBOM generation pipeline (Stage 3) |
images/variables.yml |
Defines the global cpe value |
ci/images/builder/inject-source-info.sh |
Script that creates labels.json |
macros/inject_source_info_labels.yml.j2 |
Macro that adds LABEL to Containerfile |
macros/install_newroot.yml.j2 |
Macro that invokes inject-source-info |
See Also
- Container Image Labels – complete reference for all image labels across all categories
- Image Pipeline – SBOM Generation – how the production SBOMs are built from Syft, Hermeto, and Mobster
References
- Embedded Metadata Schema
- Container-First Vulnerability Reporting (Konflux feature specification)
- VEX (Vulnerability Exploitability eXchange)
- Syft – SBOM generation tool
- Hermeto – build-time dependency provenance tool
- Mobster – SBOM merging tool
- SPDX Specification