GCVE-BCP-10 : Improved Common Platform Enumeration for GCVE

GCVE-BCP-10: Improved Common Platform Enumeration for GCVE

  • Document ID: GCVE-BCP-10
  • Title: Improved Common Platform Enumeration for GCVE
  • Status: Draft
  • Category: Best Current Practice
  • Updates: CPE-compatible naming and match semantics
  • Author: GCVE.eu
  • Intended use: Platform and product identification, applicability matching, vendor management, and synonym handling in the GCVE ecosystem

Abstract

This document specifies an improved platform enumeration format for GCVE. The format is intentionally compatible with existing Common Platform Enumeration (CPE) practices and string formats, while introducing additional metadata required for long-term maintenance and decentralized operations.

The main improvements are:

  • a stable UUID for each platform record, allowing a platform name to evolve without losing identity;
  • explicit provenance through a source field;
  • support for synonym and equivalence relationships through structured relationship objects identified by UUIDs;
  • registry support for vendor and synonym management operated by GCVE.

The goal is to preserve interoperability with existing CPE-based tooling while addressing operational limitations encountered in long-term platform naming, vendor consolidation, and alias management.

Motivation

Traditional CPE naming is useful as a compact and widely understood naming format, but it has several practical limitations:

  • the name itself often acts as the identifier;
  • renaming or normalization can break references;
  • aliases and synonyms are difficult to track cleanly;
  • provenance is not always explicit;
  • vendor mergers, splits, rebranding, and product renaming require registry-level lifecycle handling.

GCVE-BCP-10 addresses these limitations by separating the stable identity of a platform record from its displayed or canonical CPE-compatible name.

Design principles

GCVE-BCP-10 follows these principles:

  • Backward compatibility: existing CPE strings remain valid and central to matching.
  • Stable identity: a UUID is the primary durable identifier for a platform record.
  • Rename safety: canonical names may change without changing the identity of the record.
  • Explicit provenance: each record identifies its source.
  • Structured synonym handling: aliases and equivalent names are modeled as first-class relationships.
  • Registry governance: GCVE operates a registry for updates, synonym resolution, and vendor management.

Terminology

Platform record

A structured record describing one software, hardware, operating system, or application platform using a CPE-compatible identifier plus GCVE extensions.

Canonical name

The preferred CPE-compatible string currently designated by the GCVE registry for a platform record.

Alias / synonym

An alternative name that refers to the same or closely related platform identity.

Relationship

A typed link between one platform UUID and another platform UUID.

Source

The authority or dataset from which a record originates, such as GCVE, NVD, a vendor, or another recognized catalog.

Data model

GCVE-BCP-10 extends the traditional CPE representation with the following fields:

Required additions

  • platformId: a UUID representing the stable identity of the platform record.
  • source: a string identifying the source authority for the record.

Optional additions

  • canonical: boolean indicating whether the enclosed CPE-compatible name is the canonical name for that platform record.
  • relationships: an array of structured relationship objects.
  • vendorId: a stable UUID for the vendor entity, when vendor normalization is supported by the registry.
  • deprecated: boolean indicating that the record should no longer be used for new references.
  • replacedBy: UUID of the preferred replacement platform record.
  • metadata: object reserved for implementation-specific non-matching metadata.

Relationship object

Each relationship has its own UUID and typed semantics. This allows the registry to track lifecycle and provenance for alias management.

Recommended fields:

  • relationshipId: UUID of the relationship entry.
  • type: relationship type.
  • targetPlatformId: UUID of the related platform.
  • source: source authority for the relationship.
  • created: creation timestamp.
  • lastModified: last update timestamp.

Recommended relationship types

The following relationship types are defined:

  • synonym-of: the source record is a synonym of the target record.
  • canonical-of: the source record is an alias whose canonical record is the target.
  • renamed-to: the source record has been renamed to the target.
  • superseded-by: the source record is obsolete and replaced operationally by the target.
  • equivalent-to: both records are considered operationally equivalent for identification purposes.
  • vendor-merge-into: vendor/product normalization relationship, when applicable.
  • derived-from: the record was derived from another source record.

Implementations may define additional relationship types, but they should not change the semantics of the above values.

Compatibility model

GCVE-BCP-10 does not replace the CPE string format. Instead, it layers stable identity and registry semantics on top of it.

A GCVE-BCP-10 platform record:

  • must retain a CPE-compatible name string;
  • must not require existing CPE parsers to understand UUID fields to parse the string itself;
  • may provide registry metadata beyond what legacy CPE consumers understand;
  • should allow lossless round-trip preservation of the original CPE-compatible string.

This means existing tools can continue using the CPE string for matching, while GCVE-aware systems use UUIDs and relationships for lifecycle-safe management.

Proposed schema extension

The following JSON Schema extends the current CPE Match API style schema with GCVE-BCP-10 concepts while preserving compatibility.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "JSON Schema for GCVE-BCP-10 CPE-compatible Match API",
  "$id": "https://gcve.eu/schema/gcve-bcp-10/cpematch_api_json.schema",
  "definitions": {
    "def_matchstring": {
      "type": "object",
      "properties": {
        "matchString": {
          "$ref": "#/definitions/def_match_data"
        }
      },
      "required": ["matchString"],
      "additionalProperties": false
    },
    "def_relationship": {
      "type": "object",
      "properties": {
        "relationshipId": {
          "type": "string",
          "format": "uuid"
        },
        "type": {
          "type": "string",
          "enum": [
            "synonym-of",
            "canonical-of",
            "renamed-to",
            "superseded-by",
            "equivalent-to",
            "vendor-merge-into",
            "derived-from"
          ]
        },
        "targetPlatformId": {
          "type": "string",
          "format": "uuid"
        },
        "source": {
          "type": "string"
        },
        "created": {
          "type": "string",
          "format": "date-time"
        },
        "lastModified": {
          "type": "string",
          "format": "date-time"
        }
      },
      "required": [
        "relationshipId",
        "type",
        "targetPlatformId",
        "source",
        "created",
        "lastModified"
      ],
      "additionalProperties": false
    },
    "def_cpe_name": {
      "type": "object",
      "properties": {
        "cpeName": {
          "type": "string"
        },
        "cpeNameId": {
          "type": "string",
          "format": "uuid"
        },
        "platformId": {
          "type": "string",
          "format": "uuid"
        },
        "vendorId": {
          "type": "string",
          "format": "uuid"
        },
        "source": {
          "type": "string"
        },
        "canonical": {
          "type": "boolean"
        },
        "deprecated": {
          "type": "boolean"
        },
        "replacedBy": {
          "type": "string",
          "format": "uuid"
        },
        "relationships": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/def_relationship"
          }
        },
        "created": {
          "type": "string",
          "format": "date-time"
        },
        "lastModified": {
          "type": "string",
          "format": "date-time"
        },
        "metadata": {
          "type": "object"
        }
      },
      "required": [
        "cpeName",
        "cpeNameId",
        "platformId",
        "source"
      ],
      "additionalProperties": false
    },
    "def_match_data": {
      "description": "CPE-compatible match string or range with GCVE-BCP-10 extensions",
      "type": "object",
      "properties": {
        "criteria": {
          "type": "string"
        },
        "matchCriteriaId": {
          "type": "string",
          "format": "uuid"
        },
        "source": {
          "type": "string"
        },
        "versionStartExcluding": {
          "type": "string"
        },
        "versionStartIncluding": {
          "type": "string"
        },
        "versionEndExcluding": {
          "type": "string"
        },
        "versionEndIncluding": {
          "type": "string"
        },
        "created": {
          "type": "string",
          "format": "date-time"
        },
        "lastModified": {
          "type": "string",
          "format": "date-time"
        },
        "cpeLastModified": {
          "type": "string",
          "format": "date-time"
        },
        "status": {
          "type": "string"
        },
        "matches": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/def_cpe_name"
          }
        }
      },
      "required": [
        "criteria",
        "matchCriteriaId",
        "source",
        "lastModified",
        "created",
        "status"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "resultsPerPage": {
      "type": "integer"
    },
    "startIndex": {
      "type": "integer"
    },
    "totalResults": {
      "type": "integer"
    },
    "format": {
      "type": "string"
    },
    "version": {
      "type": "string"
    },
    "timestamp": {
      "type": "string",
      "format": "date-time"
    },
    "matchStrings": {
      "description": "Array of CPE-compatible match strings with GCVE-BCP-10 extensions",
      "type": "array",
      "items": {
        "$ref": "#/definitions/def_matchstring"
      }
    }
  },
  "required": [
    "resultsPerPage",
    "startIndex",
    "totalResults",
    "format",
    "version",
    "timestamp",
    "matchStrings"
  ],
  "additionalProperties": false
}

Field semantics

platformId

A stable UUID identifying the platform record independently of the textual CPE name.

Rules:

  • platformId must remain stable across renames and normalization updates.
  • a new platformId must not be assigned solely because the canonical CPE-compatible string changes.
  • if two records are merged and declared to refer to the same platform identity, registry policy determines which UUID remains canonical and which becomes deprecated.

source

The authority or origin of the record.

Examples:

  • gcve
  • nvd
  • vendor:cisco
  • vendor:microsoft
  • community
  • import:cpe-dictionary

Rules:

  • source must identify where the current record or assertion comes from.
  • implementations should preserve original provenance when importing third-party records.

relationships

An array describing aliases, renames, equivalences, and lifecycle transitions.

Rules:

  • relationships must point to another platformId;
  • relationship entries should be individually addressable and auditable through relationshipId;
  • registries should preserve historical relationships, even when a preferred canonical target exists.

canonical

Indicates whether the associated cpeName is the preferred canonical name for that platformId.

Rules:

  • a platform identity may have multiple historical or alternative names;
  • exactly one active name should be canonical within a given registry context.

deprecated and replacedBy

Lifecycle controls used when a name or record is retired.

Rules:

  • deprecated records should remain resolvable;
  • replacedBy should reference the preferred replacement UUID when applicable.

Registry behavior

GCVE operates a registry to support updates, handle synonyms, and manage vendors.

Registry responsibilities

The registry:

  • assigns and preserves platformId values;
  • tracks canonical names and aliases;
  • manages synonym and rename relationships;
  • supports vendor normalization and vendor lifecycle changes;
  • records provenance and timestamps;
  • exposes updates suitable for synchronization by external systems.

Vendor management

GCVE may maintain a distinct vendor registry, including stable vendor identifiers.

Vendor management may include:

  • normalization of spelling variants;
  • company mergers and acquisitions;
  • rebranding;
  • separation of legal vendor identity from naming conventions used in the CPE-compatible string.

A vendorId is recommended where vendor lifecycle tracking matters.

Synonym handling

GCVE should support synonym management for cases such as:

  • product renaming;
  • historical names;
  • community versus vendor-preferred naming;
  • imported external identifiers;
  • spelling normalization;
  • product line consolidation.

Synonyms should not require changing the stable platform UUID when the underlying identity is preserved.

Resolution expectations

Given any known UUID or recognized CPE-compatible alias, the registry should be able to return:

  • the current canonical name;
  • the stable platformId;
  • known synonyms;
  • lifecycle status;
  • vendor normalization data where available.

Matching behavior

GCVE-BCP-10 does not change the core CPE applicability concept. Matching is still performed using the CPE-compatible criteria and version range fields.

However, GCVE-aware systems may enhance matching by:

  • resolving synonyms before comparison;
  • canonicalizing renamed products;
  • dereferencing deprecated records to active replacements;
  • preserving provenance during matching output.

This improves consistency across datasets that use different but equivalent product names.

Example record

{
  "cpeName": "cpe:2.3:a:example:demo_product:2.4:*:*:*:*:*:*:*",
  "cpeNameId": "af6f3f91-44bb-4d9b-a2ff-3a97f6401001",
  "platformId": "f0d60d9c-95b5-4678-9004-cbc3af830001",
  "vendorId": "e2d42311-7712-4fc2-a5a5-f1cfdecc0001",
  "source": "gcve",
  "canonical": true,
  "deprecated": false,
  "created": "2026-04-03T10:00:00Z",
  "lastModified": "2026-04-03T10:00:00Z",
  "relationships": [
    {
      "relationshipId": "3f40d8fd-3d52-4965-a8dc-a7e8f55d0001",
      "type": "synonym-of",
      "targetPlatformId": "8b345eb0-46af-48b8-b8d8-2de8f2c70001",
      "source": "gcve",
      "created": "2026-04-03T10:00:00Z",
      "lastModified": "2026-04-03T10:00:00Z"
    }
  ]
}

Example match response

{
  "resultsPerPage": 1,
  "startIndex": 0,
  "totalResults": 1,
  "format": "NVD_CPEMatchString",
  "version": "2.0",
  "timestamp": "2026-04-03T10:00:00Z",
  "matchStrings": [
    {
      "matchString": {
        "criteria": "cpe:2.3:a:example:demo_product:*:*:*:*:*:*:*:*",
        "matchCriteriaId": "9b4a0fc1-7439-4cb3-bf0c-bf67fb110001",
        "source": "gcve",
        "created": "2026-04-03T10:00:00Z",
        "lastModified": "2026-04-03T10:00:00Z",
        "status": "Active",
        "versionStartIncluding": "2.0",
        "versionEndExcluding": "3.0",
        "matches": [
          {
            "cpeName": "cpe:2.3:a:example:demo_product:2.4:*:*:*:*:*:*:*",
            "cpeNameId": "af6f3f91-44bb-4d9b-a2ff-3a97f6401001",
            "platformId": "f0d60d9c-95b5-4678-9004-cbc3af830001",
            "vendorId": "e2d42311-7712-4fc2-a5a5-f1cfdecc0001",
            "source": "gcve",
            "canonical": true,
            "deprecated": false,
            "relationships": [
              {
                "relationshipId": "3f40d8fd-3d52-4965-a8dc-a7e8f55d0001",
                "type": "synonym-of",
                "targetPlatformId": "8b345eb0-46af-48b8-b8d8-2de8f2c70001",
                "source": "gcve",
                "created": "2026-04-03T10:00:00Z",
                "lastModified": "2026-04-03T10:00:00Z"
              }
            ],
            "created": "2026-04-03T10:00:00Z",
            "lastModified": "2026-04-03T10:00:00Z"
          }
        ]
      }
    }
  ]
}

Migration considerations

To migrate an existing CPE-based dataset into GCVE-BCP-10:

  • preserve existing CPE-compatible strings;
  • assign a platformId to each unique platform record;
  • assign source based on the origin of the imported entry;
  • detect aliases and represent them as relationships;
  • identify canonical names where multiple equivalent names exist;
  • keep deprecated names resolvable through replacedBy or relationship chains.

Migration should prefer stable identity over textual immutability.

Interoperability guidance

Implementations that do not understand GCVE-BCP-10 extensions may ignore fields such as:

  • platformId
  • vendorId
  • source
  • canonical
  • deprecated
  • replacedBy
  • relationships
  • metadata

As long as the criteria and cpeName strings remain valid CPE-compatible strings, interoperability with legacy parsers is preserved at the string level.

Security and integrity considerations

Consumers should not automatically trust synonym or vendor merge assertions from untrusted sources.

Implementations should consider:

  • provenance validation;
  • registry authenticity;
  • update signing;
  • auditability of relationship changes;
  • conflict handling when multiple authorities disagree about canonicalization.

Stable UUIDs reduce ambiguity, but trust still depends on the authority maintaining the registry.

Summary

GCVE-BCP-10 improves CPE operations without discarding CPE compatibility. It introduces:

  • stable platform UUIDs;
  • explicit source attribution;
  • structured synonym and rename relationships;
  • registry-based vendor and lifecycle management.

These extensions make platform identification more durable, auditable, and maintainable in real-world vulnerability and asset management workflows.

Suggested minimal compliance profile

An implementation conforms to GCVE-BCP-10 minimal profile if it:

  • supports CPE-compatible strings;
  • assigns a stable platformId UUID to each platform record;
  • includes a source field;
  • can express at least synonym-of and renamed-to relationships;
  • preserves deprecated records without breaking resolution.

A full-featured GCVE registry implementation should additionally support:

  • vendor normalization with vendorId;
  • canonical name resolution;
  • replacement and deprecation workflows;
  • history tracking for record and relationship changes.
1 Like

Before going for BCP-10, we will test with an experimental online application to handling of CPE. Maybe then we could refine the BCP-10 format.

First version of the CPE Collaborative Editor released:

No login required, just proposal. And then approved.

Still missing the interface for the relationships.

1 Like

First off, great work on GCVE-BCP-10 — the direction here is exactly right. Separating stable UUID identity from the mutable CPE name string is the most important architectural decision this ecosystem needs, and the backward-compatibility-first approach makes adoption realistic rather than aspirational. The inclusion of a concrete JSON Schema and a minimal compliance profile are also really appreciated — they lower the barrier to implementation significantly.

That said, I have a few suggestions I think would strengthen the proposal:

UUID Generation Strategy
The document requires platformId to be stable, but doesn’t specify how UUIDs should be generated. Without guidance, two independent implementations could assign different UUIDs to the same platform, which would quietly break interoperability. A non-normative appendix recommending something like UUIDv5 with a GCVE namespace would go a long way here.

Conflict Resolution
The security section acknowledges that multiple authorities may disagree on canonicalization, but there’s no mechanism for resolving it. Even a simple priority ordering — GCVE registry > vendor assertion > community — would give implementers something to stand on.

Governance
This is probably the biggest long-term risk. “GCVE operates a registry” and “registry policy determines” appear several times, but there’s no description of how that policy is formed, who can propose changes, or how disputes get resolved. Even a brief stub pointing to a future governance document would signal that this is being thought about.

Bidirectional Relationship Consistency
The relationship model is directional, but it’s unclear whether both ends are required to declare the relationship. If record A declares synonym-of to B, must B declare canonical-of back to A? Without a consistency rule, consumers will encounter incomplete or contradictory graphs.

A Few Smaller Items

  • The metadata field is wide open — I’d recommend at least a warning against using it for matching purposes and a suggestion to namespace keys (e.g., "gcve:internal", "vendor:rogolabs") to prevent collisions down the road.
  • The example match response hardcodes "format": "NVD_CPEMatchString" — should this be GCVE_CPEMatchString to distinguish it from NVD’s schema?
  • CPE 2.2 (URI binding) is still widespread. It would help to explicitly state whether CPE 2.2 strings are valid cpeName values or whether migration to 2.3 is expected.
  • Worth linking the CPE Collaborative Editor directly from the BCP document itself, not just in the thread comments — it’s the reference implementation and deserves that visibility.

None of this is meant to slow things down — the foundation is solid and worth building on. Happy to help draft any of these additions if useful. Looking forward to seeing where this goes!

1 Like

Thanks a lot for the feedback and ideas. Many of your points align with issues we are currently facing in different parts of the format. We are still quite far from having something fully functional ;-).

I will reply with a separate message for each point to make follow-up easier.

UUID

Initially, I tried using UUIDv5 generation with a fixed PSK/NS to ensure consistency. The problem I ran into was data mirroring between vendors and products. In that case, I cannot use the same UUIDv5 for both, as this would create collisions and break uniqueness.

One possible approach would have been to use two PSKs/NS: one for vendors and one for products, in order to keep them separate. However, that introduces another issue, as you start to lose some visibility into the namespace within the UUID itself.

Because of that, I moved back to UUIDv4 generation. However, this also introduces the difficulty of non-deterministic UUID generation and the need to trust the initial import. The initial prototype use the example below and I detached from the original JSON format of NVD.

Another idea would have been to use a fixed UUIDv5, with the string representation including a prefix such as nist-cpe:<UUID> or gcve-cpe:<UUID>. This could allow the use of custom PSKs or namespaces, which could in fact be derived directly from the namespace itself and calculated easily. It would also mean that, when dealing with a standalone UUID, its origin would be immediately identifiable by default. My only fear is that we don’t the unicity clear and we have many synonyms between namespace without solving the original issue.

So still wondering what’s best UUID strategy for the entries.

Example of a proposed format

Vendor Element

    {
      "created_at": "2026-04-06T15:15:32.668186",
      "name": "misp",
      "notes": null,
      "title": "Misp",
      "updated_at": "2026-04-06T15:15:32.668187",
      "uuid": "62653321-c513-556c-a889-ef681b72044b"
    },
    {
      "created_at": "2026-04-06T19:26:27.980637",
      "name": "1000projects",
      "notes": "Test vendor",
      "title": "1000Projects",
      "updated_at": "2026-04-07T06:49:57.740094",
      "uuid": "080f2149-7a52-507c-aae7-66120f8ff911"
    },

Relationships

    {
      "approved_at": "2026-04-07T10:00:58.144175",
      "created_at": "2026-04-07T10:00:58.150844",
      "rationale": "",
      "relationship_type": "superseded-by",
      "source_product_uuid": null,
      "source_vendor_uuid": "080f2149-7a52-507c-aae7-66120f8ff911",
      "submitted_at": "2026-04-07T10:00:37.953639",
      "submitter_email": "",
      "submitter_name": "",
      "target_product_uuid": null,
      "target_vendor_uuid": "62653321-c513-556c-a889-ef681b72044b",
      "updated_at": "2026-04-07T10:00:58.150846"
    }

Thanks for breaking this down, Alexandre.

I’m a big advocate for staying the course with UUIDv5 here. Moving back to UUIDv4 feels like a step toward a ‘central registry’ model, which eventually creates a sync nightmare for anyone trying to mirror or contribute to the data independently. If two people create a record for a new vendor at the same time, UUIDv4 guarantees they’ll have different IDs; UUIDv5 guarantees they’ll have the same one.

Regarding the collision issue between vendors and products sharing the same name (like ‘misp’), have you considered using Type-Specific Namespaces?

Instead of one namespace for all GCVE entries, you could derive sub-namespaces:

  • Vendor Namespace: UUIDv5(GCVE_ROOT, "vendor")

  • Product Namespace: UUIDv5(GCVE_ROOT, "product")

Then, the Vendor ID for ‘misp’ becomes UUIDv5(Vendor_Namespace, "misp") and the Product ID becomes UUIDv5(Product_Namespace, "misp"). They will never collide, even with identical strings.

This keeps the system deterministic and decentralized, which I think is vital for the long-term health of the format. Plus, it solves the ‘trust the initial import’ problem because the data validates the ID.

1 Like