Skip to content

Commit 95714d8

Browse files
authored
fix: modernize cvss score loading (#4373)
* fixes #4370 Turns out our cvss score loading code was out of date and thus wasn't loading scores correctly and was throwing off a lot of log messages. I've also added some basic input validation to the cvss data just in case. Signed-off-by: Terri Oda <[email protected]>
1 parent 6c38177 commit 95714d8

File tree

1 file changed

+73
-20
lines changed

1 file changed

+73
-20
lines changed

cve_bin_tool/data_sources/nvd_source.py

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -247,27 +247,80 @@ def format_data_api2(self, all_cve_entries):
247247
continue
248248

249249
# Multiple ways of including CVSS metrics.
250-
cve_cvss = cve_item
251-
if "metrics" in cve_item:
250+
# Newer data uses "impact" -- we may wish to delete the old below
251+
252+
# sometimes (frequently?) the impact is empty
253+
if "impact" in cve_item:
254+
if "baseMetricV3" in cve_item["impact"]:
255+
cve["CVSS_version"] = 3
256+
if "cvssV3" in cve_item["impact"]["baseMetricV3"]:
257+
# grab either the data or some default values
258+
cve["severity"] = cve_item["impact"]["baseMetricV3"][
259+
"cvssV3"
260+
].get("baseSeverity", "UNKNOWN")
261+
cve["score"] = cve_item["impact"]["baseMetricV3"]["cvssV3"].get(
262+
"baseScore", 0
263+
)
264+
cve["CVSS_vector"] = cve_item["impact"]["baseMetricV3"][
265+
"cvssV3"
266+
].get("vectorString", "")
267+
268+
# severity is in a different spot in v2 versus v3
269+
elif "baseMetricV2" in cve_item["impact"]:
270+
cve["CVSS_version"] = 2
271+
cve["severity"] = cve_item["impact"]["baseMetricV4"].get(
272+
"severity", "UNKNOWN"
273+
)
274+
if "cvssV2" in cve_item["impact"]["baseMetricV2"]:
275+
cve["score"] = cve_item["impact"]["baseMetricV2"]["cvssV2"].get(
276+
"baseScore", 0
277+
)
278+
cve["CVSS_vector"] = cve_item["impact"]["baseMetricV2"][
279+
"cvssV2"
280+
].get("vectorString", "")
281+
282+
# Old data used "metrics" -- This section may need to be deleted
283+
elif "metrics" in cve_item:
252284
cve_cvss = cve_item["metrics"]
253-
# Get CVSSv3 or CVSSv2 score
254-
cvss_available = True
255-
if "cvssMetricV31" in cve_cvss:
256-
cvss_data = cve_cvss["cvssMetricV31"][0]["cvssData"]
257-
cve["CVSS_version"] = 3
258-
elif "cvssMetricV30" in cve_cvss:
259-
cvss_data = cve_cvss["cvssMetricV30"][0]["cvssData"]
260-
cve["CVSS_version"] = 3
261-
elif "cvssMetricV2" in cve_cvss:
262-
cvss_data = cve_cvss["cvssMetricV2"][0]["cvssData"]
263-
cve["CVSS_version"] = 2
264-
else:
265-
LOGGER.debug(f"Unknown CVSS metrics field {cve_item['id']}")
266-
cvss_available = False
267-
if cvss_available:
268-
cve["severity"] = cvss_data.get("baseSeverity", "UNKNOWN")
269-
cve["score"] = cvss_data.get("baseScore", 0)
270-
cve["CVSS_vector"] = cvss_data.get("vectorString", "")
285+
286+
# Get CVSSv3 or CVSSv2 score
287+
cvss_available = True
288+
if "cvssMetricV31" in cve_cvss:
289+
cvss_data = cve_cvss["cvssMetricV31"][0]["cvssData"]
290+
cve["CVSS_version"] = 3
291+
elif "cvssMetricV30" in cve_cvss:
292+
cvss_data = cve_cvss["cvssMetricV30"][0]["cvssData"]
293+
cve["CVSS_version"] = 3
294+
elif "cvssMetricV2" in cve_cvss:
295+
cvss_data = cve_cvss["cvssMetricV2"][0]["cvssData"]
296+
cve["CVSS_version"] = 2
297+
else:
298+
cvss_available = False
299+
if cvss_available:
300+
cve["severity"] = cvss_data.get("baseSeverity", "UNKNOWN")
301+
cve["score"] = cvss_data.get("baseScore", 0)
302+
cve["CVSS_vector"] = cvss_data.get("vectorString", "")
303+
# End old metrics section
304+
305+
# do some basic input validation checks
306+
# severity should be alphanumeric
307+
if not cve["severity"].isalnum():
308+
self.logger.debug(
309+
f"Severity for {cve['id']} is invalid: {cve['severity']}"
310+
)
311+
cve["severity"] = re.sub(r"[\W]", "", cve["severity"])
312+
313+
# score should be numeric
314+
try:
315+
cve["score"] = float(cve["score"])
316+
except ValueError:
317+
self.logger.debug(f"Score for {cve['id']} is invalid: {cve['score']}")
318+
cve["score"] = "invalid"
319+
320+
# CVSS_vector will be validated/normalized when cvss library is used but
321+
# we can at least do a character filter here
322+
# we expect letters (mostly but not always uppercase), numbers, : and /
323+
cve["CVSS_vector"] = re.sub("[^A-Za-z0-9:/]", "", cve["CVSS_vector"])
271324

272325
cve_data.append(cve)
273326

0 commit comments

Comments
 (0)