From e46783d3a0f56c93c2ad28236162ff4b05c134df Mon Sep 17 00:00:00 2001 From: Thomas Perale Date: Fri, 29 May 2026 17:06:27 +0200 Subject: [PATCH] support/scripts/cve-check: fix vulnerability timestamp to RFC 3339 Normalize vulnerability timestamps to RFC 3339 format with explicit UTC timezone suffix for CycloneDX 1.6 compliance. This fixes validation errors in sbom-utility and makes the generated SBOM with vulnerabilities compatible with DependencyTrack VEX parsers. The NVD JSON data feeds provide timestamps in ISO 8601 format without timezone information (e.g., "1999-01-01T05:00:00.000"), but CycloneDX 1.6 requires RFC 3339 format with explicit timezone designation (e.g., "1999-01-01T05:00:00.000Z"). Add nvd_datetime_to_rfc3339() helper function to convert timestamps before serialization. Validation results: Before fix: $ sbom-utility validate -i cve/cve_report_current.json [INFO] BOM valid against JSON schema: 'false' [INFO] (234) schema errors detected. Error example: { "type": "format", "field": "vulnerabilities.0.updated", "context": "(root).vulnerabilities.0.updated", "description": "Does not match format 'date-time'", "value": "2025-04-03T01:03:51.193" } After fix: $ sbom-utility validate -i cve/cve_report_update.json [INFO] BOM valid against JSON schema: 'true' Tested-with: sbom-utility v0.18.1 Co-authored-by: Fabien Lehoussel Signed-off-by: Thomas Perale Signed-off-by: Thomas Petazzoni --- support/scripts/cve-check | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/support/scripts/cve-check b/support/scripts/cve-check index bcd970bad8..5047523ade 100755 --- a/support/scripts/cve-check +++ b/support/scripts/cve-check @@ -12,10 +12,10 @@ from collections import defaultdict from pathlib import Path from typing import TypedDict +from datetime import datetime, timezone import argparse import sys import json - import cve as cvecheck @@ -35,6 +35,24 @@ locally. brpath = Path(__file__).parent.parent.parent +def datetime_to_rfc3339(dt_string): + """Normalize datetime string to RFC 3339 format with Z suffix. + + NVD dates are already in ISO format, just need to add the Z suffix. + + Input: "1999-01-01T05:00:00.000" + Output: "1999-01-01T05:00:00.000Z" + """ + dt = datetime.fromisoformat(dt_string.replace('Z', '+00:00')) + + if dt.tzinfo is None: + dt = dt.replace(tzinfo=timezone.utc) + else: + dt = dt.astimezone(timezone.utc) + + return dt.isoformat().replace('+00:00', 'Z') + + def cve_api_get_lang_from_list(values, lang="en") -> (str | None): for x in values: if x.get("lang") == lang: @@ -134,10 +152,10 @@ def nvd_cve_to_cdx_vulnerability(nvd_cve): "url": f"https://nvd.nist.gov/vuln/detail/{nvd_cve['id']}" }, **({ - "published": nvd_cve["published"], + "published": datetime_to_rfc3339(nvd_cve["published"]), } if "published" in nvd_cve else {}), **({ - "updated": nvd_cve["lastModified"], + "updated": datetime_to_rfc3339(nvd_cve["lastModified"]), } if "lastModified" in nvd_cve else {}), **({ "cwes": nvd_cve_weaknesses_to_cdx(nvd_cve["weaknesses"]),