Skip to content

Commit

Permalink
fix: modernize cvss score loading (#4373)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
terriko authored Aug 29, 2024
1 parent 6c38177 commit 95714d8
Showing 1 changed file with 73 additions and 20 deletions.
93 changes: 73 additions & 20 deletions cve_bin_tool/data_sources/nvd_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,27 +247,80 @@ def format_data_api2(self, all_cve_entries):
continue

# Multiple ways of including CVSS metrics.
cve_cvss = cve_item
if "metrics" in cve_item:
# Newer data uses "impact" -- we may wish to delete the old below

# sometimes (frequently?) the impact is empty
if "impact" in cve_item:
if "baseMetricV3" in cve_item["impact"]:
cve["CVSS_version"] = 3
if "cvssV3" in cve_item["impact"]["baseMetricV3"]:
# grab either the data or some default values
cve["severity"] = cve_item["impact"]["baseMetricV3"][
"cvssV3"
].get("baseSeverity", "UNKNOWN")
cve["score"] = cve_item["impact"]["baseMetricV3"]["cvssV3"].get(
"baseScore", 0
)
cve["CVSS_vector"] = cve_item["impact"]["baseMetricV3"][
"cvssV3"
].get("vectorString", "")

# severity is in a different spot in v2 versus v3
elif "baseMetricV2" in cve_item["impact"]:
cve["CVSS_version"] = 2
cve["severity"] = cve_item["impact"]["baseMetricV4"].get(
"severity", "UNKNOWN"
)
if "cvssV2" in cve_item["impact"]["baseMetricV2"]:
cve["score"] = cve_item["impact"]["baseMetricV2"]["cvssV2"].get(
"baseScore", 0
)
cve["CVSS_vector"] = cve_item["impact"]["baseMetricV2"][
"cvssV2"
].get("vectorString", "")

# Old data used "metrics" -- This section may need to be deleted
elif "metrics" in cve_item:
cve_cvss = cve_item["metrics"]
# Get CVSSv3 or CVSSv2 score
cvss_available = True
if "cvssMetricV31" in cve_cvss:
cvss_data = cve_cvss["cvssMetricV31"][0]["cvssData"]
cve["CVSS_version"] = 3
elif "cvssMetricV30" in cve_cvss:
cvss_data = cve_cvss["cvssMetricV30"][0]["cvssData"]
cve["CVSS_version"] = 3
elif "cvssMetricV2" in cve_cvss:
cvss_data = cve_cvss["cvssMetricV2"][0]["cvssData"]
cve["CVSS_version"] = 2
else:
LOGGER.debug(f"Unknown CVSS metrics field {cve_item['id']}")
cvss_available = False
if cvss_available:
cve["severity"] = cvss_data.get("baseSeverity", "UNKNOWN")
cve["score"] = cvss_data.get("baseScore", 0)
cve["CVSS_vector"] = cvss_data.get("vectorString", "")

# Get CVSSv3 or CVSSv2 score
cvss_available = True
if "cvssMetricV31" in cve_cvss:
cvss_data = cve_cvss["cvssMetricV31"][0]["cvssData"]
cve["CVSS_version"] = 3
elif "cvssMetricV30" in cve_cvss:
cvss_data = cve_cvss["cvssMetricV30"][0]["cvssData"]
cve["CVSS_version"] = 3
elif "cvssMetricV2" in cve_cvss:
cvss_data = cve_cvss["cvssMetricV2"][0]["cvssData"]
cve["CVSS_version"] = 2
else:
cvss_available = False
if cvss_available:
cve["severity"] = cvss_data.get("baseSeverity", "UNKNOWN")
cve["score"] = cvss_data.get("baseScore", 0)
cve["CVSS_vector"] = cvss_data.get("vectorString", "")
# End old metrics section

# do some basic input validation checks
# severity should be alphanumeric
if not cve["severity"].isalnum():
self.logger.debug(
f"Severity for {cve['id']} is invalid: {cve['severity']}"
)
cve["severity"] = re.sub(r"[\W]", "", cve["severity"])

# score should be numeric
try:
cve["score"] = float(cve["score"])
except ValueError:
self.logger.debug(f"Score for {cve['id']} is invalid: {cve['score']}")
cve["score"] = "invalid"

# CVSS_vector will be validated/normalized when cvss library is used but
# we can at least do a character filter here
# we expect letters (mostly but not always uppercase), numbers, : and /
cve["CVSS_vector"] = re.sub("[^A-Za-z0-9:/]", "", cve["CVSS_vector"])

cve_data.append(cve)

Expand Down

0 comments on commit 95714d8

Please sign in to comment.