@@ -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