Use a package URL (purl) as the primary identifier for packages found in ecosystems like npm, Maven or PyPI, because it names the exact package and version. Add a CPE when a vulnerability source matches on it. A purl identifies a specific package, while a CPE names a class of product.
What each one is
A purl is a URL with the form scheme, type, namespace, name, version, qualifiers and subpath. The scheme is always pkg, and the type is the ecosystem, for example maven, npm, nuget, gem or pypi. The specification says a purl is useful to reliably reference the same software package. It is an Ecma standard, ECMA-427.
A CPE, Common Platform Enumeration, is a standard way to describe classes of applications, operating systems and hardware. NIST says it names product classes, not specific installed instances. CPE 2.3 is the published version in use, and a 3.0 effort is early and will not retire 2.3.
Side by side
| Question | Package URL | CPE |
|---|---|---|
| Names | One package in one ecosystem | A class of product |
| Ecosystem aware | Yes, built into the type | No |
| Example | pkg:pypi/django@1.11.1 | A vendor, product and version string |
| Standard | ECMA-427 | NIST CPE 2.3 |
| Suited to | Libraries and packages | Operating systems, hardware, products without a package ecosystem |
Which to use when
- Open source library from a package manager: purl.
- OS package in a container: purl with the distro type and qualifiers such as distro and architecture.
- Commercial product or hardware without a package ecosystem: CPE, and a purl if one exists.
- Anything you plan to match against a feed that uses CPE: add both.
The OpenVEX specification recommends the purl as the identifier and accepts CPE as an alternative. If your SBOM has no purls, mapping a VEX statement to a component becomes guesswork.
What goes wrong with weak identifiers
- A name with no ecosystem can match the wrong package, since different registries reuse names.
- A CPE written by hand or guessed by a tool can miss the real entry, producing a false negative.
- Dropping qualifiers, such as architecture or repository, merges components that are different builds.
A practical test: take ten components from your SBOM and look each one up in a vulnerability database by its identifier. If the lookup is exact for nine and ambiguous for one, you have found the weak spot. It is usually a component with no ecosystem, a renamed fork, or a vendored copy. Fix those identifiers first, since they are the ones most likely to hide a real finding.
Quick check
Do I need both in every component?
No. Prefer the purl for packages. Add a CPE only where a data source needs it.
Is a purl a download link?
No. It is an identifier. It does not tell you where to fetch the package.
Safeguard's SBOM and dependency scanning covers SBOM ingestion and dependency scanning, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.