Data quality

How to fix missing purl and CPE identifiers

A practical method for adding package URLs and CPE names to embedded components, without inventing identities that break matching.

The problem: Your SBOM validator reports components without a purl or CPE. You need to add identifiers, but the packages come from Buildroot, Yocto, a vendor SDK and a few binary blobs.

purl and CPE solve different problems

purl (Package URL)
A structured, package-manager-aware identifier: scheme pkg, type, namespace, name, version, qualifiers and subpath. It is the identifier open-source advisory feeds prefer for libraries.
CPE
NIST's product dictionary entry (vendor, product, version, update and so on). It is broader and lossier, but for a commercial or renamed component it may be the only identifier a feed understands.

A component may legitimately carry both. What it must not carry is a purl that claims an ecosystem the component does not come from, because that produces a confident wrong match.

Step 1 — classify each unidentifiable component

Component originIdentifier to useWatch out for
Distro or Yocto/Buildroot packagepurl with the real type, namespace and versionImage-recipe versions that differ from the upstream source
Language package (npm, PyPI, Cargo, Go)purl with the ecosystem typeLockfile ranges instead of resolved versions
Upstream library compiled inpurl matching the upstream releaseVendor patch level; add qualifiers only if a feed understands them
Commercial SDK or radio moduleCPE when the vendor publishes CVE-assigned products, otherwise a vendor-described componentDo not fabricate pkg:generic entries
Bootloader or RTOS componentpurl if it is released upstream, CPE if the vendor tracks it that wayOften outside open-source advisory coverage entirely

Step 2 — build the purl from the source of truth

Generate the identifier where the version is already known: the recipe, the lockfile, the package manifest. Hand-editing a finished SBOM is how identity errors enter.

{
  "type": "library",
  "name": "openssl"
}

{
  "type": "library",
  "bom-ref": "pkg:generic/[email protected]",
  "name": "openssl",
  "version": "3.0.13",
  "purl": "pkg:generic/[email protected]",
  "supplier": { "name": "OpenSSL Software Foundation" }
}

Keep the version inside both the version field and the purl. A purl without a version field, or a version field that contradicts the purl, is one of the most common causes of a component that looks identified but never matches.

Step 3 — use CPE deliberately

  • Use CPE 2.3 formatted strings with an explicit version when the vendor tracks products that way.
  • Do not attach a CPE for a similar-sounding product. A wrong CPE produces false positives that are harder to disprove than a missing identifier.
  • Never use the any-version wildcard to make a component look covered; it cannot be resolved to a specific advisory state.
  • If neither identifier is meaningful, say so in the component and in your risk assessment instead of filling the field.

Step 4 — re-validate and check the reason changed

Re-run the validator and compare the readiness reasons before and after. The number of query-ready components should rise, and the remaining reasons should be ones you can explain: an unsupported ecosystem, an ambiguous identity, a vendor component with no feed coverage.

If a component moves from “missing identifier” to “query ready” but your scanning result does not change, the problem is downstream of the SBOM: the matcher's ecosystem coverage, not the document.

Scope and limits

  • A syntactically valid purl does not guarantee that any advisory feed knows the package.
  • This guide covers identifier quality only; it does not assess exploitability or product risk.

Sources

Next step

Open the validator and check your components