To deduplicate components across SBOMs, convert each to a canonical identifier, ideally a normalized purl, and use ecosystem, name and version as the merge key. Keep the raw identifiers as aliases. Merge by identifier, not by display name, and never merge across ecosystems.
Why the same component looks different
Three suppliers may all ship the same library, yet one writes the name in capitals, one adds a vendor prefix, and one gives a CPE only. If you count by string you will believe you have three components when you have one, and a vulnerability search will miss two of them.
The identifier hierarchy
| Rank | Identifier | Notes |
|---|---|---|
| 1 | purl | Names a package uniformly across ecosystems |
| 2 | Hash of the artifact | Strong when present, ties to exact bytes |
| 3 | CPE | Product naming, looser fit for packages |
| 4 | Name plus version plus ecosystem | Last resort, lower confidence |
CycloneDX lets a component assert identity by purl or CPE, and says a purl must be valid under the purl specification. Reject or flag invalid ones first, otherwise bad strings pollute the key.
Normalization rules
- Scope the name to its ecosystem. The OSV schema states that a package name is meaningful only inside its ecosystem, so an npm package and a PyPI package with the same name are different packages.
- Normalize case and separators according to each ecosystem's rules, not a global rule.
- Strip qualifiers that do not affect identity when building the key, such as a download URL, but keep them in the raw record.
- Keep the version string exactly. Do not coerce versions into a different scheme.
- Record aliases so you can search by any of the originals.
The merge key
Use a composite: ecosystem, normalized name, exact version. For records with a hash, add the hash as an additional match, and when it conflicts with the key, flag for review. A same version with a different hash is worth attention.
What not to merge
- Two forks of the same project with different maintainers.
- Components that share a name in different ecosystems.
- A vendored copy and the upstream package, unless you can show they are the same bytes.
Measure the result
After you deduplicate, report distinct components, distinct versions per component, and number of products per component. The last number is most useful in an incident, because it tells you how many places a fix has to land.
Try it yourself
Click through it at your own pace, or open it full screen.
Pick a package and see how many places it shows up in the inventory.
Where Safeguard fits
Safeguard provides SBOM and dependency scanning and asset discovery to build a single inventory. The free scan gives a quick look.
Quick check
Can I merge on name and version alone?
Only within one ecosystem. Add the ecosystem to the key.
What if two SBOMs give the same version but different hashes?
Flag it for review. Release artifacts are expected to be identical for the same version.
Sources
- CycloneDX 1.6 JSON reference: purl and cpe identity fields.
- OSV schema: package names scoped to ecosystem.
- Package-URL introduction: purl as uniform identifier.
Last reviewed: 19 October 2026.