Skip to content

[BUG] npm sbom emits duplicate entries in CycloneDX dependsOn / SPDX relationships when a node has multiple edges to the same name@version (incomplete fix for #6967) #9310

@mikaelkristiansson

Description

@mikaelkristiansson

Is there an existing issue for this?

  • I have searched the existing issues

This issue exists in the latest npm version

  • I am using the latest npm

Current Behavior

#6967 (PR #7992, shipped in 11.13.0) deduplicates top-level entries in components / dependencies (CycloneDX) and packages (SPDX) by name@version. However the per-node child arrays — CycloneDX dependsOn and
SPDX DEPENDENCY_OF relationships — are still emitted without deduplication.

This happens whenever a single node has multiple edgesOut resolving to the same name@version. The most common trigger is npm's package aliasing, where a package.json declares both a direct dependency and an alias
to the same underlying package:

{
  "dependencies": {
    "lodash": "^4.17.21",
    "lodash-aliased": "npm:lodash@^4.17.21"
  }
}

Both edges resolve to lodash@4.18.1. In lib/utils/sbom-cyclonedx.js, toCyclonedxDependency does:

dependsOn: [...node.edgesOut.values()]
  .filter(edge => nodes.find(n => n === edge.to))
  .map(edge => toCyclonedxID(edge.to))
  .filter(id => id),

toCyclonedxID returns ${packageName}@${version}, so two edges to the same package collapse to the same string and both end up in the array. The same shape exists in lib/utils/sbom-spdx.js for DEPENDENCY_OF
relationships.

CycloneDX 1.5 schema requires dependsOn arrays to have unique items, so downstream consumers that validate against the schema (e.g. Dependency Track) reject the SBOM:

$.dependencies[1557].dependsOn: must have only unique items in the array

Expected Behavior

Each dependsOn array (CycloneDX) and each set of DEPENDENCY_OF relationships from a single source (SPDX) contains a given name@version at most once.

Steps To Reproduce

  mkdir sbom-alias-repro && cd sbom-alias-repro
  cat > package.json <<'EOF'
  {
    "name": "sbom-alias-repro",
    "version": "1.0.0",
    "dependencies": {
      "lodash": "^4.17.21",
      "lodash-aliased": "npm:lodash@^4.17.21"
    }
  }
  EOF
  npm install --package-lock-only
  npm sbom --sbom-format cyclonedx --package-lock-only | jq '.dependencies[0]'

Output (npm 11.13.0):

{
  "ref": "sbom-alias-repro@1.0.0",
  "dependsOn": [
    "lodash@4.18.1",
    "lodash@4.18.1"
  ]
}

The same project with --sbom-format spdx emits two identical DEPENDENCY_OF relationships from lodash to the root package.

Environment

  • npm: 11.13.0
  • Node.js: 22.22.2
  • OS: macOS (also reproduces on Linux CI)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bugthing that needs fixingNeeds Triageneeds review for next steps

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions