Skip to content

Commit 77a1610

Browse files
fix: add CVSSv4 support to auditjs parser and improve error handling (#12391)
* fix: add CVSSv4 support to auditjs parser and improve error handling * fix: add CVSSv4 support to auditjs parser and improve error handling * lint: fix exception style, add CVSS4.0 vector to description * tests: Add tests for CVSS V2 and V4 vectors and update scan examples * docs: Correct comment text * temp: add local parse_cvss_from_text until upstream PR is merged * docs: fix docstring formatting to comply with D413 * Update dojo/tools/auditjs/parser.py * Update dojo/tools/auditjs/parser.py --------- Co-authored-by: valentijnscholten <valentijnscholten@gmail.com>
1 parent 7a0bdb1 commit 77a1610

File tree

5 files changed

+500
-398
lines changed

5 files changed

+500
-398
lines changed

dojo/tools/auditjs/parser.py

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,50 @@
22
import re
33
from json.decoder import JSONDecodeError
44

5-
import cvss.parser
6-
from cvss import CVSS2, CVSS3
5+
# import cvss.parser
6+
from cvss import CVSS2, CVSS3, CVSS4, CVSSError
77

88
from dojo.models import Finding
99

1010

11+
# TEMPORARY: Local implementation until the upstream PR is merged & released: https://github.com/RedHatProductSecurity/cvss/pull/75
12+
def parse_cvss_from_text(text):
13+
"""
14+
Parses CVSS2, CVSS3, and CVSS4 vectors from arbitrary text and returns a list of CVSS objects.
15+
16+
Parses text for substrings that look similar to CVSS vector
17+
and feeds these matches to CVSS constructor.
18+
19+
Args:
20+
text (str): arbitrary text
21+
22+
Returns:
23+
A list of CVSS objects.
24+
25+
"""
26+
# Looks for substrings that resemble CVSS2, CVSS3, or CVSS4 vectors.
27+
# CVSS3 and CVSS4 vectors start with a 'CVSS:x.x/' prefix and are matched by the optional non-capturing group.
28+
# CVSS2 vectors do not include a prefix and are matched by raw vector pattern only.
29+
# Minimum total match length is 26 characters to reduce false positives.
30+
matches = re.compile(r"(?:CVSS:[3-4]\.\d/)?[A-Za-z:/]{26,}").findall(text)
31+
32+
cvsss = set()
33+
for match in matches:
34+
try:
35+
if match.startswith("CVSS:4."):
36+
cvss = CVSS4(match)
37+
elif match.startswith("CVSS:3."):
38+
cvss = CVSS3(match)
39+
else:
40+
cvss = CVSS2(match)
41+
42+
cvsss.add(cvss)
43+
except (CVSSError, KeyError):
44+
pass
45+
46+
return list(cvsss)
47+
48+
1149
class AuditJSParser:
1250

1351
"""Parser for AuditJS Scan tool"""
@@ -85,33 +123,38 @@ def get_findings(self, filename, test):
85123
if cwe_find:
86124
cwe = int(cwe_find[0][4:])
87125
else:
88-
msg = (
89-
"Missing mandatory attributes (id, title, description). Please check your report or ask "
90-
"community."
91-
)
126+
msg = "Missing mandatory attributes (id, title, description). Please check your report or ask community."
92127
raise ValueError(msg)
93128
if "cvssScore" in vulnerability:
94129
cvss_score = vulnerability["cvssScore"]
95130
if "cvssVector" in vulnerability:
96-
cvss_vectors = cvss.parser.parse_cvss_from_text(
131+
cvss_vectors = parse_cvss_from_text(
97132
vulnerability["cvssVector"],
98133
)
99-
if len(cvss_vectors) > 0 and isinstance(
100-
cvss_vectors[0], CVSS3,
101-
):
102-
# Only set finding vector if it's version 3
103-
cvss_vector = cvss_vectors[0].clean_vector()
104-
severity = cvss_vectors[0].severities()[0]
105-
elif len(cvss_vectors) > 0 and isinstance(
106-
cvss_vectors[0], CVSS2,
107-
):
108-
# Otherwise add it to description
109-
description = (
110-
description
111-
+ "\nCVSS V2 Vector:"
112-
+ cvss_vectors[0].clean_vector()
113-
)
114-
severity = cvss_vectors[0].severities()[0]
134+
135+
if len(cvss_vectors) > 0:
136+
vector_obj = cvss_vectors[0]
137+
138+
if isinstance(vector_obj, CVSS4):
139+
description += "\nCVSS V4 Vector:" + vector_obj.clean_vector()
140+
severity = vector_obj.severities()[0]
141+
142+
elif isinstance(vector_obj, CVSS3):
143+
cvss_vector = vector_obj.clean_vector()
144+
severity = vector_obj.severities()[0]
145+
146+
elif isinstance(vector_obj, CVSS2):
147+
description += "\nCVSS V2 Vector:" + vector_obj.clean_vector()
148+
severity = vector_obj.severities()[0]
149+
150+
else:
151+
msg = "Unsupported CVSS version detected in parser."
152+
raise ValueError(msg)
153+
else:
154+
# Explicitly raise an error if no CVSS vectors are found,
155+
# to avoid 'NoneType' errors during severity processing later.
156+
msg = "No CVSS vectors found. Please check that parse_cvss_from_text() correctly parses the provided cvssVector."
157+
raise ValueError(msg)
115158
else:
116159
# If there is no vector, calculate severity based on
117160
# score and CVSS V3 (AuditJS does not always include

0 commit comments

Comments
 (0)