Skip to content

Generate OCI PURLs for local images without digests #9399

@knqyf263

Description

@knqyf263

Description

Currently, when Trivy scans locally built Docker images that don't have RepoDigests (i.e., images that haven't been pushed to a registry), it doesn't generate an OCI PURL in the output. This causes the purl field to be null, which makes it difficult to apply vulnerability suppressions, like VEX, consistently.

Problem

When scanning local images without RepoDigests, Trivy's CycloneDX output shows:

{
  "metadata": {
    "component": {
      "type": "container",
      "name": "test:latest",
      "bom-ref": "3ff14136-e09f-4df9-80ea-000000000002",
      "purl": null
    }
  }
}

The missing PURL prevents:

  • Consistent VEX matching across different scanning contexts
  • Reliable vulnerability suppression for local development workflows
  • Proper SBOM identification when images are scanned before being pushed to registries

Current Design Rationale

The current behavior of not generating PURLs for local container images was intentional. Since PURLs are defined to "identify and locate" software packages, generating PURLs for local container images seemed incorrect because:

  • Local images cannot be located from outside the host machine
  • We cannot obtain the repository digest that would serve as the version component in the PURL
  • The absence of RepoDigests indicates the image hasn't been distributed

This was considered the correct behavior according to the original interpretation of the PURL specification.

Proposed Solution

After reviewing the PURL specification discussions, we've concluded that using OCI PURLs primarily for identity (rather than location) doesn't violate the specification. Therefore, we can always generate OCI PURLs for container images, even when they lack RepoDigests.

For local images, use the image name from RepoTags to construct a valid PURL with repository_url as an optional hint qualifier.

Expected Behavior

After the fix, local images should generate proper PURLs:

Local image with latest tag:

{
  "metadata": {
    "component": {
      "type": "container",
      "name": "test:latest",
      "bom-ref": "pkg:oci/test?repository_url=index.docker.io%2Flibrary%2Ftest&arch=amd64",
      "purl": "pkg:oci/test?repository_url=index.docker.io%2Flibrary%2Ftest&arch=amd64"
    }
  }
}

Local image with specific tag:

{
  "metadata": {
    "component": {
      "type": "container",
      "name": "test:v1.0",
      "bom-ref": "pkg:oci/test?repository_url=index.docker.io%2Flibrary%2Ftest&tag=v1.0&arch=amd64",
      "purl": "pkg:oci/test?repository_url=index.docker.io%2Flibrary%2Ftest&tag=v1.0&arch=amd64"
    }
  }
}

Discussed in #9381

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/featureCategorizes issue or PR as related to a new feature.scan/vulnerabilityIssues relating to vulnerability scanning

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions