diff --git a/depscan/lib/analysis.py b/depscan/lib/analysis.py index 70d4580c..86262b72 100644 --- a/depscan/lib/analysis.py +++ b/depscan/lib/analysis.py @@ -19,7 +19,7 @@ from rich.tree import Tree from vdb.lib import CPE_FULL_REGEX from vdb.lib.config import placeholder_exclude_version, placeholder_fix_version -from vdb.lib.utils import parse_cpe, parse_purl +from vdb.lib.utils import get_cvss3_from_vector, get_cvss4_from_vector, parse_cpe, parse_purl from depscan.lib import config from depscan.lib.logger import LOG, console @@ -336,6 +336,11 @@ def prepare_vdr(options: PrepareVdrOptions): justify = "right" table.add_column(header=h, justify=justify, vertical="top") for vuln_occ_dict in options.results: + # If CVSS v4 data is available, override the severity and cvss_score + if vuln_occ_dict.get("cvss4_vector_string"): + cvss4_obj = get_cvss4_from_vector(vuln_occ_dict.get("cvss4_vector_string")) + vuln_occ_dict["cvss_score"] = cvss4_obj.get("baseScore") + vuln_occ_dict["severity"] = cvss4_obj.get("baseSeverity").upper() vid = vuln_occ_dict.get("id") problem_type = vuln_occ_dict.get("problem_type") cwes = [] @@ -1026,34 +1031,33 @@ def cvss_to_vdr_rating(vuln_occ_dict): :return: A list containing a dictionary with CVSS score information. """ - cvss_score = vuln_occ_dict.get("cvss_score", 2.0) - with contextlib.suppress(ValueError, TypeError): - cvss_score = float(cvss_score) - if (pkg_severity := vuln_occ_dict.get("severity", "").lower()) not in ( - "critical", - "high", - "medium", - "low", - "info", - "none", - ): - pkg_severity = "unknown" - ratings = [ - { - "score": cvss_score, - "severity": pkg_severity, - } - ] - method = "31" + ratings = [] + # Support for cvss v4 + if vuln_occ_dict.get("cvss4_vector_string") and (vector_string := vuln_occ_dict.get("cvss4_vector_string")): + cvss4_obj = get_cvss4_from_vector(vector_string) + ratings.append( + { + "method": "CVSSv4", + "score": cvss4_obj.get("baseScore"), + "severity": cvss4_obj.get("baseSeverity").lower(), + "vector": vector_string + } + ) if vuln_occ_dict.get("cvss_v3") and ( vector_string := vuln_occ_dict["cvss_v3"].get("vector_string") ): - ratings[0]["vector"] = vector_string with contextlib.suppress(CVSSError): - method = cvss.CVSS3(vector_string).as_json().get("version") + cvss3_obj = get_cvss3_from_vector(vector_string) + method = cvss3_obj.get("version") method = method.replace(".", "").replace("0", "") - ratings[0]["method"] = f"CVSSv{method}" - + ratings.append( + { + "method": f"CVSSv{method}", + "score": cvss3_obj.get("baseScore"), + "severity": cvss3_obj.get("baseSeverity").lower(), + "vector": vector_string + } + ) return ratings diff --git a/pyproject.toml b/pyproject.toml index d1945484..4d3a13e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,12 @@ [project] name = "owasp-depscan" -version = "5.4.8" +version = "5.5.0" description = "Fully open-source security audit for project dependencies based on known vulnerabilities and advisories." authors = [ {name = "Team AppThreat", email = "cloud@appthreat.com"}, ] dependencies = [ - "appthreat-vulnerability-db==5.7.8", + "appthreat-vulnerability-db==5.8.1", "defusedxml", "oras~=0.1.26", "PyYAML", diff --git a/test/test_analysis.py b/test/test_analysis.py index 6efc8ca8..3a9ad9fb 100644 --- a/test/test_analysis.py +++ b/test/test_analysis.py @@ -708,8 +708,7 @@ def test_cvss_to_vdr_rating(): "severity": "HIGH", } # Test missing score and vector string - assert cvss_to_vdr_rating(res) == [ - {'method': 'CVSSv31', 'score': 2.0, 'severity': 'high'}] + assert cvss_to_vdr_rating(res) == [] # Test parsing res["cvss_v3"]["vector_string"] = ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I" ":N/A:H") @@ -729,6 +728,24 @@ def test_cvss_to_vdr_rating(): 'severity': 'high', 'vector': 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H' }] + assert cvss_to_vdr_rating({ + "cvss_v3": { + "vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:H" + }, + "cvss4_vector_string": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:H/SA:H" + }) == [{ + 'method': 'CVSSv4', + 'score': 7.9, + 'severity': 'high', + 'vector': 'CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:H/SA:H' + }, + { + 'method': 'CVSSv31', + 'score': 10.0, + 'severity': 'critical', + 'vector': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:H' + } + ] def test_get_version_range():