GCVE BCP-05 drafting - Best practices for the "container" format - modified CVE Record Format

In BCP-03, we only describe the protocol and not the format. Nevertheless, we recommend using the CVE Record Format. During some tests with a new GNA, we discovered areas for improvement, and insightful feedback about the format was provided.

We actually added the vulnId field in the CVE Record Format to support GNA publication with their own IDs, which addressed an issue raised by one of the GNAs.

BCP-05 will clarify this point, as well as the specific part about namespace usage in the format. This is particularly relevant for the Vulnerability Lookup implementation, which uses namespaces to avoid field collisions in case the format evolves.

There are still some open questions, such as:

  • Should BCP-05 allow other formats?
  • Should extensions or additional information (similar to ADP) be permitted for CVEs?
  • Since Vulnerability Lookup allows forking an existing CVE into a local instance, should a GNA explicitly indicate when a vulnerability has been forked?

@cedric what do you think about this? especially the last open question.

Hi Alex

As we just discussed, in my thinking the following ideas could be considered:

  1. Writing explicitly that 1 vulnerability identifier can be assigned maximum to 1 vulnerability, but with GCVE you can of course create multiple different forks for any needs to express different instances of the vulnerability.
  2. Writing that identified or CVD’d vulnerabilities that are accepted MUST be assigned a vulnerability identifier, silent patching is not ok
  3. 3 potential public data points for a CVD process, all 3 optional and filled out by the researcher disclosing: (1: Date disclosed to company X for product Y or similar, 2: Date accepted as a vulnerability, 3: Date agreement on impact reached)
1 Like

Thanks for the ideas.

For (1), we can add this recommendation to BCP-04 but also to BCP-02 (or clarify it, as it was already mentioned).

For (2), it is a requirement. We have already mentioned this in BCP-02, but we may want to expand it further.

Regarding the timeline, it is indeed a recommended best practice in BCP-02. However, for the data format, we rarely see this implemented. It might therefore make sense to define an extended field that could include additional information, in addition to the default CVEv5 format fields: datePublished, dateReserved, and dateUpdated.

So with point (2):

Writing that identified or CVD’d vulnerabilities that are accepted MUST be assigned a vulnerability identifier, silent patching is not ok.

First off, I love it. I care a lot about the hidden harm silent patches. That said, this is a pretty hefty must, and also lacks a time bounding. Can I express this in a GCVE record with a future date? Any bounding there, or can I conditionIrelease on the appearance of the rise of the God-Emporer of Mankind?

So, I do like requiring disclosure. I don’t like breaking the spec just because I haven’t disclosed yet. It’s a common practice in many places use CVE IDs as internal numbers pre-disclosure, since it’s easier than switching to a new identifier when you disclose, and some places wait until disclosure to assign. I’d prefer the former to be encouraged, and suggest at minimum, requiring some specific date, (ISO-8601 formatted). This can encourage tooling to either auto-disclose, or notify when the imagined future date is passed.

@adulau mentioned that (2) is already a requirement, pointing at BCP-02. Ctrl-F’ing for all the “musts” in there turns up 6, and they’re not capitalized MUSTs, so may not be intended as RFC 2119 keywords.

Anyway, this is about a disclosure requirement. I have other thoughts. More coming soon!

All right, general considerations on a spec. I will admit, I haven’t processed BCP-02 to a point of understandingness, so I didn’t really consider it when I whipped up a spec over here. My bad.

Also, that spec is trash, and should not be used. It was an experiment to see what GCVE would do with it, derived mostly from a reading of BCP-03, which states today, “GCVE-BCP-03 does not enforce a specific JSON format for vulnerability publication.” Challenge accepted!

That said, I would strongly advise against just piggy-backing on CVE JSONv5. There is a ton of stuff in there that is obtuse, occult, and difficult for newcomers to get a handle on.

Incidentally, it’s also encumbered by mysterious trademarks, which may or may not be enforceable in all kinds of jurisdictions around the world. OSVDB ran into this kind of problem in the long-ago. The current license appears very permissive, but who knows how long that’ll last.

GCVE seems to want to be a drop-in replacement for CVE in case Something Happens with CVE (namely, the infrastructure). This is laudable and noble. So, the name of the game is a format that is both compatible with CVE, and distinct from CVE, much like how Samba interoperates with SMB. Below are some philosophical options. I’m sure there are goals and desires for GCVE that I haven’t thought of.

(1) GCVE is a drop in replacement. A valid GCVE record is a CVE record natively, and no conversion is required. A well-formed CVE record is also a well-formed GCVE record. Backwards compatibility is guaranteed, but in practice, this is tricky if GCVE has MUSTs that CVE does not, since you’ll break the GCVE spec with an otherwise valid CVE record.

(2) Post-processing CVEs into GCVEs. A valid GCVE record can be derived from a valid CVE record with some processing. A GNA would only need to convert once and publish that, and the conversion is trivially implementable. GNA-0 and GNA-1 could do it, and so could anyone else. This is appealing if you have additional musts, and it’s probably possible to encode those MUSTs in some of the free-form fields already present in CVE. It also means you can throw out a bunch of things that you don’t care about (unless one of those things is required in CVE records).

(3) Ignore CVE altogether. This is what I did. It didn’t work out well. Conversions between the two are bespoke, artisanal solutions per GNA. This would be intentionally breaking the relationship between GCVE and CVE records, and would certainly make it clear that GCVE is not CVE. GNA-1 can handle the conversion from CVE, publish how they do it, populate GNA-0’s corpus of vulnerabilities on the CVE Project’s behalf. However, it would also reject those CVEs that don’t meet GCVE’s requirements. Backwards compatibility is totally off the table, and while some overlap is expected, it won’t be perfect, and consumers who want both will need solutions to ingest both, and choose which GNA to believe.

Notionally, I like all of these. I’d lean toward (2), but it means a bunch of work to make GNA-0 sensible, and you’re restricted on what’s a reasonable MUST for GCVE.

Finally: it’s entirely possible that CVE infrastructure, the online services, and the day-to-day operational work that is conducted by the MITRE corporation and paid for exclusively by US taxpayers and via the US Department of Homeland Security is not going be disrupted by political forces in February of 2026. I have no hard evidence this sad fate is in the offing. Every current employee of DHS and MITRE I’ve spoken to as of this post in August of 2025 has assured me of their personal, continuing faith in the survivability of the CVE Program, irrespective of other unforeseen and unprecedented cancellations of public-good, well-established, and critically important US government programs.

This is all to say that it’s wise to at least maintain easy compatibility with CVE records. This means ensuring that GCVE records are easily translatable to CVE records, and vice-versa.

1 Like

Thanks a lot for the insightful details. I think I fully agree with you on most points. That’s why we didn’t want to pursue option (3) (as the process is long and painful even if we manage to do it for one specific format in the past decade), as creating a new format was never really our objective.

Another important aspect is that we wanted to maintain compatibility with the current CNA process for CVE records. This is already the case in Vulnerability-Lookup, since we use Vulnogram to edit, fork, or publish vulnerabilities. This setup allows anyone with a CNA API ID to publish their vulnerabilities as a GNA, either to the CNA CVE Program or to alternative models that may emerge due to geopolitical or technical or organisational instability.

Concerning BCP-03, we will update it to reflect that the format description will be moved to BCP-05. The current model, of course, is to adopt the standard CVE format as described.

The only issue is the extension, particularly for the minimal identifier required for GCVE and GNA. One option would be to include a GCVE-specific field, which could then be stripped out to remain fully compatible when publishing as a CNA (in the CVE Program), for example.

My optimistic approach would be to request a custom field from the CVE Program and ask them to include it in the specification. Nevertheless, knowing how complex it can be with standards committees (I won’t name any here), we could instead adopt the approach of stripping the field whenever we need to produce fully compliant JSON files, even if requesting the addition of a new field from a committee might take years.

  • (Action 1) To summarise, my plan for the document (unless there is a major technical disagreement) is to update BCP-03 and release a new version specifying that we adhere to the CVE Record Format, with details and extensions described in BCP-05.

  • (Action 2) Agreement on the current extended field in the CVE Record Format. We may need to have a discussion about the different approaches, especially regarding the current implementation in Vulnerability-Lookup (@cedric, I’m looking at you ;-)) if we keep the current strategy (fields mentioned at the beginning of this thread) or update it with a single dictionary.

  • (Action 3) Open an issue on the CVE Record Format repository for the field(s) described in the BCP-05 draft to explore whether inclusion is possible. This action might take years, but it’s not blocking us :wink:

As an example, I have included a GCVE vulnerability in the CVE Record Format, with the extended field. This can serve as a basis for discussion.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "cerebrate",
          "programFiles": [
            "‎src/Controller/UserSettingsController.php"
          ],
          "repo": "https://github.com/cerebrate-project/cerebrate/",
          "vendor": "cerebrate",
          "versions": [
            {
              "status": "affected",
              "version": "1.27"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Jeroen Pinoy"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "Incorrect ACL for user settings edit, which previously allowed enumeration of usernames."
            }
          ],
          "value": "Incorrect ACL for user settings edit, which previously allowed enumeration of usernames."
        }
      ],
      "impacts": [
        {
          "capecId": "CAPEC-118",
          "descriptions": [
            {
              "lang": "en",
              "value": "CAPEC-118 Collect and Analyze Information"
            }
          ]
        }
      ],
      "metrics": [
        {
          "cvssV4_0": {
            "Automatable": "NOT_DEFINED",
            "Recovery": "NOT_DEFINED",
            "Safety": "NOT_DEFINED",
            "attackComplexity": "LOW",
            "attackRequirements": "NONE",
            "attackVector": "NETWORK",
            "baseScore": 9.3,
            "baseSeverity": "CRITICAL",
            "privilegesRequired": "HIGH",
            "providerUrgency": "NOT_DEFINED",
            "subAvailabilityImpact": "HIGH",
            "subConfidentialityImpact": "HIGH",
            "subIntegrityImpact": "HIGH",
            "userInteraction": "ACTIVE",
            "valueDensity": "NOT_DEFINED",
            "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
            "version": "4.0",
            "vulnAvailabilityImpact": "HIGH",
            "vulnConfidentialityImpact": "HIGH",
            "vulnIntegrityImpact": "HIGH",
            "vulnerabilityResponseEffort": "NOT_DEFINED"
          },
          "format": "CVSS",
          "scenarios": [
            {
              "lang": "en",
              "value": "GENERAL"
            }
          ]
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-203",
              "description": "CWE-203 Observable Discrepancy",
              "lang": "en",
              "type": "CWE"
            }
          ]
        },
        {
          "descriptions": [
            {
              "cweId": "CWE-204",
              "description": "CWE-204 Observable Response Discrepancy",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "orgId": "00000000-0000-4000-9000-000000000000"
      },
      "references": [
        {
          "tags": [
            "patch"
          ],
          "url": "https://github.com/cerebrate-project/cerebrate/commit/04fb2cd4bb45566308930029f63096942f658b86"
        }
      ],
      "source": {
        "discovery": "INTERNAL"
      },
      "x_generator": {
        "engine": "Vulnogram 0.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "00000000-0000-4000-9000-000000000000",
    "datePublished": "2025-08-22T12:33:00.000Z",
    "dateUpdated": "2025-08-23T07:55:10.950332Z",
    "requesterUserId": "00000000-0000-4000-9000-000000000000",
    "serial": 1,
    "state": "PUBLISHED",
    "vulnId": "GCVE-1-2025-0003",
    "vulnerabilitylookup_history": [
      [
        "alexandre.dulaunoy@circl.lu",
        "2025-08-22T12:33:56.492006Z"
      ],
      [
        "cedric.bonhomme@circl.lu",
        "2025-08-23T07:47:34.139577Z"
      ],
      [
        "cedric.bonhomme@circl.lu",
        "2025-08-23T07:55:10.950332Z"
      ]
    ]
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.1"
}

First proposal for (Action 1):

Updates/improvement welcome

For the moment in cveMetadata we have added:

  • .cveMetadata.vulnId , and
  • .cveMetadata.vulnerabilitylookup_history

Also, for your information it is possible to get the following metadata fields via Vulnerability-Lookup:

  • vulnerability-lookup:meta → meta information related to the vuln from sources like vulnrichment or NVD
  • vulnerability-lookup:linked → correlations with vulnerabilities from various sources (GHSA, PySec, CSAF, etc.)
  • vulnerability-lookup:bundles → related bundles
  • vulnerability-lookup:comments → related comments
  • vulnerability-lookup:sightings → related sightings

Contrary to vulnId and vulnerabilitylookup_history, these fields are not really part of the CVE data, they are added dynamically.
These fields are tied to Vulnerability-Lookup, and GCVE should be software-agnostic. So I do not think we should touch this.

Just an example:

$ curl --silent 'https://vulnerability.circl.lu/api/vulnerability/CVE-2025-2842?with_meta=false&with_linked=false&with_comments=true&with_bundles=true&with_sightings=true' \
  -H 'accept: application/json' \
  | jq '.["vulnerability-lookup:sightings"]'
[
  {
    "uuid": "81e07178-6279-4a63-b4ec-ef6b33d8227f",
    "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd",
    "author": "9f56dd64-161d-43a6-b9c3-555944290a09",
    "vulnerability": "CVE-2025-2842",
    "type": "seen",
    "source": "https://bsky.app/profile/cve.skyfleet.blue/post/3lltgrtfeee2i",
    "creation_timestamp": "2025-04-02T12:56:47.602210Z"
  }
]

Now back to our main problem, putting vulnId in cveMetadata was a pragmatic choice at a precise moment, and the goal was to not touch the existing cveId field. With minor changes to the JSON schema of CVE v5.
I still like this idea… But now I am thinking that we could as well have the field in: .gcveMetadata.vulnId.

So we should maybe push to have our own gcveMetadata container where we can have vulnId.

For example in this container we could also have:

  • a flag to indicate if the GCVE is a fork of a CVE or not
  • our own dates (published, updated, reserved). Dates from cveMetadata will remain the default. We only specify dates in .gcveMetadata if needed
  • state
  • …

This is just an example, but it would give us a structured way to extend GCVE without polluting the CVE metadata. GCVE could have it’s own metadata !

About fork, actually if in the JSON there is a ‘vulnId’ and a ‘cveId’ the corresponding GCVE should logically be a fork.

1 Like

Thanks, this sounds like a plan. Should we go ahead and create a gcveMetadata container in Vulnerability-Lookup to see how the implementation could work? Then we could share this implementation description with the CVE Program.