Skip to content

Commit 840b13a

Browse files
authored
fix: correctly utilize CVSSv4 from ossindex (#7899)
1 parent 2dd7324 commit 840b13a

File tree

2 files changed

+133
-1
lines changed

2 files changed

+133
-1
lines changed

core/src/main/java/org/owasp/dependencycheck/analyzer/OssIndexAnalyzer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import io.github.jeremylong.openvulnerability.client.nvd.CvssV2;
2121
import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data;
22+
import io.github.jeremylong.openvulnerability.client.nvd.CvssV4;
2223
import org.sonatype.ossindex.service.api.componentreport.ComponentReport;
2324
import org.sonatype.ossindex.service.api.componentreport.ComponentReportVulnerability;
2425
import org.sonatype.ossindex.service.api.cvss.Cvss2Severity;
@@ -321,7 +322,9 @@ private Vulnerability transform(final ComponentReport report, final ComponentRep
321322
final double cvssScore = source.getCvssScore() != null ? source.getCvssScore().doubleValue() : -1;
322323

323324
if (source.getCvssVector() != null) {
324-
if (source.getCvssVector().startsWith("CVSS:3")) {
325+
if (source.getCvssVector().startsWith("CVSS:4")) {
326+
result.setCvssV4(CvssUtil.vectorToCvssV4("ossindex", CvssV4.Type.PRIMARY, cvssScore, source.getCvssVector()));
327+
} else if (source.getCvssVector().startsWith("CVSS:3")) {
325328
result.setCvssV3(CvssUtil.vectorToCvssV3(source.getCvssVector(), cvssScore));
326329
} else {
327330
// convert cvss details

core/src/main/java/org/owasp/dependencycheck/utils/CvssUtil.java

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@
2121
import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data;
2222
import io.github.jeremylong.openvulnerability.client.nvd.CvssV3;
2323
import io.github.jeremylong.openvulnerability.client.nvd.CvssV3Data;
24+
2425
import java.util.Arrays;
2526
import java.util.HashMap;
2627
import java.util.List;
28+
import java.util.Map;
29+
30+
import io.github.jeremylong.openvulnerability.client.nvd.CvssV4;
31+
import io.github.jeremylong.openvulnerability.client.nvd.CvssV4Data;
2732
import org.sonatype.ossindex.service.api.cvss.Cvss3Severity;
2833

2934
/**
@@ -36,6 +41,7 @@ public final class CvssUtil {
3641
private CvssUtil() {
3742
//empty constructor for utility class.
3843
}
44+
3945
/**
4046
* The CVSS v3 Base Metrics (that are required by the spec for any CVSS v3
4147
* Vector String)
@@ -221,6 +227,129 @@ public static CvssV3 vectorToCvssV3(String vectorString, Double baseScore) {
221227
baseSeverity, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
222228
final CvssV3 cvss = new CvssV3(null, null, data, null, null);
223229
return cvss;
230+
}
231+
232+
private static CvssV4Data.SeverityType toSeverityType(double baseScore) {
233+
if (baseScore == 0.0) {
234+
return CvssV4Data.SeverityType.NONE;
235+
} else if (baseScore >= 0.1 && baseScore <= 3.9) {
236+
return CvssV4Data.SeverityType.LOW;
237+
} else if (baseScore >= 4.0 && baseScore <= 6.9) {
238+
return CvssV4Data.SeverityType.MEDIUM;
239+
} else if (baseScore >= 7.0 && baseScore <= 8.9) {
240+
return CvssV4Data.SeverityType.HIGH;
241+
} else if (baseScore >= 9.0 && baseScore <= 10.0) {
242+
return CvssV4Data.SeverityType.CRITICAL;
243+
} else {
244+
throw new IllegalArgumentException("Invalid CVSS base score: " + baseScore);
245+
}
246+
}
247+
248+
/**
249+
* Convert a CVSSv4 vector String into a CvssV4 Object.
250+
*
251+
* @param source the source of the CVSS data
252+
* @param type the type of CVSS data (primary or secondary)
253+
* @param baseScore the base score
254+
* @param vectorString the vector string
255+
* @return the CVSSv4 object
256+
*/
257+
public static CvssV4 vectorToCvssV4(String source, CvssV4.Type type, Double baseScore, String vectorString) {
258+
// Remove "CVSS:" prefix and split by "/"
259+
String[] parts = vectorString.replaceFirst("^CVSS:", "").split("/");
260+
Map<String, String> values = new HashMap<>();
261+
for (String part : parts) {
262+
String[] kv = part.split(":");
263+
if (kv.length == 2) {
264+
values.put(kv[0], kv[1]);
265+
}
266+
}
267+
268+
CvssV4Data.Version version = CvssV4Data.Version.fromValue(values.getOrDefault("4.0", "4.0"));
269+
270+
CvssV4Data.AttackVectorType attackVector = values.containsKey("AV") ? CvssV4Data.AttackVectorType.fromValue(values.get("AV")) : null;
271+
CvssV4Data.AttackComplexityType attackComplexity = values.containsKey("AC") ? CvssV4Data.AttackComplexityType.fromValue(values.get("AC")) : null;
272+
CvssV4Data.AttackRequirementsType attackRequirements = values.containsKey("AT") ? CvssV4Data.AttackRequirementsType.fromValue(values.get("AT")) : null;
273+
CvssV4Data.PrivilegesRequiredType privilegesRequired = values.containsKey("PR") ? CvssV4Data.PrivilegesRequiredType.fromValue(values.get("PR")) : null;
274+
CvssV4Data.UserInteractionType userInteraction = values.containsKey("UI") ? CvssV4Data.UserInteractionType.fromValue(values.get("UI")) : null;
275+
CvssV4Data.CiaType vulnConfidentialityImpact = values.containsKey("VC") ? CvssV4Data.CiaType.fromValue(values.get("VC")) : null;
276+
CvssV4Data.CiaType vulnIntegrityImpact = values.containsKey("VI") ? CvssV4Data.CiaType.fromValue(values.get("VI")) : null;
277+
CvssV4Data.CiaType vulnAvailabilityImpact = values.containsKey("VA") ? CvssV4Data.CiaType.fromValue(values.get("VA")) : null;
278+
CvssV4Data.CiaType subConfidentialityImpact = values.containsKey("SC") ? CvssV4Data.CiaType.fromValue(values.get("SC")) : null;
279+
CvssV4Data.CiaType subIntegrityImpact = values.containsKey("SI") ? CvssV4Data.CiaType.fromValue(values.get("SI")) : null;
280+
CvssV4Data.CiaType subAvailabilityImpact = values.containsKey("SA") ? CvssV4Data.CiaType.fromValue(values.get("SA")) : null;
281+
CvssV4Data.ExploitMaturityType exploitMaturity = values.containsKey("E") ? CvssV4Data.ExploitMaturityType.fromValue(values.get("E")) : CvssV4Data.ExploitMaturityType.NOT_DEFINED;
282+
CvssV4Data.CiaRequirementType confidentialityRequirement = values.containsKey("CR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("CR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED;
283+
CvssV4Data.CiaRequirementType integrityRequirement = values.containsKey("IR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("IR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED;
284+
CvssV4Data.CiaRequirementType availabilityRequirement = values.containsKey("AR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("AR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED;
285+
CvssV4Data.ModifiedAttackVectorType modifiedAttackVector = values.containsKey("MAV") ? CvssV4Data.ModifiedAttackVectorType.fromValue(values.get("MAV")) : CvssV4Data.ModifiedAttackVectorType.NOT_DEFINED;
286+
CvssV4Data.ModifiedAttackComplexityType modifiedAttackComplexity = values.containsKey("MAC") ? CvssV4Data.ModifiedAttackComplexityType.fromValue(values.get("MAC")) : CvssV4Data.ModifiedAttackComplexityType.NOT_DEFINED;
287+
CvssV4Data.ModifiedAttackRequirementsType modifiedAttackRequirements = values.containsKey("MAT") ? CvssV4Data.ModifiedAttackRequirementsType.fromValue(values.get("MAT")) : CvssV4Data.ModifiedAttackRequirementsType.NOT_DEFINED;
288+
CvssV4Data.ModifiedPrivilegesRequiredType modifiedPrivilegesRequired = values.containsKey("MPR") ? CvssV4Data.ModifiedPrivilegesRequiredType.fromValue(values.get("MPR")) : CvssV4Data.ModifiedPrivilegesRequiredType.NOT_DEFINED;
289+
CvssV4Data.ModifiedUserInteractionType modifiedUserInteraction = values.containsKey("MUI") ? CvssV4Data.ModifiedUserInteractionType.fromValue(values.get("MUI")) : CvssV4Data.ModifiedUserInteractionType.NOT_DEFINED;
290+
CvssV4Data.ModifiedCiaType modifiedVulnConfidentialityImpact = values.containsKey("MVC") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVC")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED;
291+
CvssV4Data.ModifiedCiaType modifiedVulnIntegrityImpact = values.containsKey("MVI") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVI")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED;
292+
CvssV4Data.ModifiedCiaType modifiedVulnAvailabilityImpact = values.containsKey("MVA") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVA")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED;
293+
CvssV4Data.ModifiedSubCType modifiedSubConfidentialityImpact = values.containsKey("MSC") ? CvssV4Data.ModifiedSubCType.fromValue(values.get("MSC")) : CvssV4Data.ModifiedSubCType.NOT_DEFINED;
294+
CvssV4Data.ModifiedSubIaType modifiedSubIntegrityImpact = values.containsKey("MSI") ? CvssV4Data.ModifiedSubIaType.fromValue(values.get("MSI")) : CvssV4Data.ModifiedSubIaType.NOT_DEFINED;
295+
CvssV4Data.ModifiedSubIaType modifiedSubAvailabilityImpact = values.containsKey("MSA") ? CvssV4Data.ModifiedSubIaType.fromValue(values.get("MSA")) : CvssV4Data.ModifiedSubIaType.NOT_DEFINED;
296+
CvssV4Data.SafetyType safety = values.containsKey("S") ? CvssV4Data.SafetyType.fromValue(values.get("S")) : CvssV4Data.SafetyType.NOT_DEFINED;
297+
CvssV4Data.AutomatableType automatable = values.containsKey("AU") ? CvssV4Data.AutomatableType.fromValue(values.get("AU")) : CvssV4Data.AutomatableType.NOT_DEFINED;
298+
CvssV4Data.RecoveryType recovery = values.containsKey("R") ? CvssV4Data.RecoveryType.fromValue(values.get("R")) : CvssV4Data.RecoveryType.NOT_DEFINED;
299+
CvssV4Data.ValueDensityType valueDensity = values.containsKey("V") ? CvssV4Data.ValueDensityType.fromValue(values.get("V")) : CvssV4Data.ValueDensityType.NOT_DEFINED;
300+
CvssV4Data.VulnerabilityResponseEffortType vulnerabilityResponseEffort = values.containsKey("RE") ? CvssV4Data.VulnerabilityResponseEffortType.fromValue(values.get("RE")) : CvssV4Data.VulnerabilityResponseEffortType.NOT_DEFINED;
301+
CvssV4Data.ProviderUrgencyType providerUrgency = values.containsKey("U") ? CvssV4Data.ProviderUrgencyType.fromValue(values.get("U")) : CvssV4Data.ProviderUrgencyType.NOT_DEFINED;
302+
303+
CvssV4Data.SeverityType baseSeverity = toSeverityType(baseScore);
304+
// Scores and severities are not present in the vector string, set to null/defaults
305+
Double threatScore = null;
306+
CvssV4Data.SeverityType threatSeverity = null;
307+
Double environmentalScore = null;
308+
CvssV4Data.SeverityType environmentalSeverity = null;
309+
310+
CvssV4Data cvssData = new CvssV4Data(
311+
version,
312+
vectorString,
313+
attackVector,
314+
attackComplexity,
315+
attackRequirements,
316+
privilegesRequired,
317+
userInteraction,
318+
vulnConfidentialityImpact,
319+
vulnIntegrityImpact,
320+
vulnAvailabilityImpact,
321+
subConfidentialityImpact,
322+
subIntegrityImpact,
323+
subAvailabilityImpact,
324+
exploitMaturity,
325+
confidentialityRequirement,
326+
integrityRequirement,
327+
availabilityRequirement,
328+
modifiedAttackVector,
329+
modifiedAttackComplexity,
330+
modifiedAttackRequirements,
331+
modifiedPrivilegesRequired,
332+
modifiedUserInteraction,
333+
modifiedVulnConfidentialityImpact,
334+
modifiedVulnIntegrityImpact,
335+
modifiedVulnAvailabilityImpact,
336+
modifiedSubConfidentialityImpact,
337+
modifiedSubIntegrityImpact,
338+
modifiedSubAvailabilityImpact,
339+
safety,
340+
automatable,
341+
recovery,
342+
valueDensity,
343+
vulnerabilityResponseEffort,
344+
providerUrgency,
345+
baseScore,
346+
baseSeverity,
347+
threatScore,
348+
threatSeverity,
349+
environmentalScore,
350+
environmentalSeverity
351+
);
224352

353+
return new CvssV4(source, type, cvssData);
225354
}
226355
}

0 commit comments

Comments
 (0)