Skip to content

Commit

Permalink
Fix: Allowing VEX import to audit all vulnerability sources
Browse files Browse the repository at this point in the history
Taking into account Steve insights

Signed-off-by: syalioune <sy_alioune@yahoo.fr>
  • Loading branch information
syalioune committed Apr 11, 2023
1 parent 8820f9b commit 4db8420
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 5 deletions.
7 changes: 6 additions & 1 deletion src/main/java/org/dependencytrack/model/Vulnerability.java
Expand Up @@ -53,6 +53,7 @@
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -107,7 +108,11 @@ public enum Source {
RETIREJS, // Retire.js
INTERNAL, // Internally-managed (and manually entered) vulnerability
OSV, // Google OSV Advisories
SNYK, // Snyk Purl Vulnerability
SNYK; // Snyk Purl Vulnerability

public static boolean isKnownSource(String source) {
return Arrays.stream(values()).anyMatch(enumSource -> enumSource.name().equalsIgnoreCase(source));
}
}

@PrimaryKey
Expand Down
Expand Up @@ -42,13 +42,16 @@ public class CycloneDXVexImporter {

public void applyVex(final QueryManager qm, final Bom bom, final Project project) {
if (bom.getVulnerabilities() == null) return;
for (org.cyclonedx.model.vulnerability.Vulnerability cdxVuln: bom.getVulnerabilities()) {
List<org.cyclonedx.model.vulnerability.Vulnerability> auditableVulnerabilities = bom.getVulnerabilities().stream().filter(
bomVuln -> bomVuln.getSource() == null || Vulnerability.Source.isKnownSource(bomVuln.getSource().getName())
).toList();
for (org.cyclonedx.model.vulnerability.Vulnerability cdxVuln: auditableVulnerabilities) {
if (cdxVuln.getAnalysis() == null) continue;
final List<Vulnerability> vulns = qm.getVulnerabilities(project, true);
if (vulns == null) continue;
for (final Vulnerability vuln: vulns) {
// NOTE: These vulnerability objects are detached
if (vuln.getVulnId().equals(cdxVuln.getId())) {
if (shouldAuditVulnerability(cdxVuln, vuln)) {

if (cdxVuln.getAffects() == null) continue;
for (org.cyclonedx.model.vulnerability.Vulnerability.Affect affect: cdxVuln.getAffects()) {
Expand Down Expand Up @@ -77,6 +80,13 @@ public void applyVex(final QueryManager qm, final Bom bom, final Project project
}
}

private boolean shouldAuditVulnerability(org.cyclonedx.model.vulnerability.Vulnerability bomVulnerability, Vulnerability dtVulnerability) {
boolean result = true;
result = result && dtVulnerability.getVulnId().equals(bomVulnerability.getId());
result = result && (bomVulnerability.getSource() == null || dtVulnerability.getSource().equalsIgnoreCase(bomVulnerability.getSource().getName()));
return result;
}

private void updateAnalysis(final QueryManager qm, final Component component, final Vulnerability vuln,
final org.cyclonedx.model.vulnerability.Vulnerability cdxVuln) {
// The vulnerability object is detached, so refresh it.
Expand Down
Expand Up @@ -46,7 +46,23 @@ public void shouldAuditVulnerabilityFromAllSourcesUsingVex() throws URISyntaxExc

List<org.cyclonedx.model.vulnerability.Vulnerability> audits = new LinkedList<>();

// Vulnerabilities for the VEX are dynamically built for each available vulnerability source
var unknownSourceVulnerability = new Vulnerability();
unknownSourceVulnerability.setVulnId("CVE-2020-25649");
unknownSourceVulnerability.setSource(Vulnerability.Source.NVD);
unknownSourceVulnerability.setSeverity(Severity.HIGH);
unknownSourceVulnerability.setComponents(List.of(component));
unknownSourceVulnerability = qm.createVulnerability(unknownSourceVulnerability, false);
qm.addVulnerability(unknownSourceVulnerability, component, AnalyzerIdentity.NONE);

var mismatchSourceVulnerability = new Vulnerability();
mismatchSourceVulnerability.setVulnId("CVE-2020-25650");
mismatchSourceVulnerability.setSource(Vulnerability.Source.NVD);
mismatchSourceVulnerability.setSeverity(Severity.HIGH);
mismatchSourceVulnerability.setComponents(List.of(component));
mismatchSourceVulnerability = qm.createVulnerability(mismatchSourceVulnerability, false);
qm.addVulnerability(mismatchSourceVulnerability, component, AnalyzerIdentity.NONE);

// Build vulnerabilities for each available and known vulnerability source
for (var source : sources) {
var vulnId = source.name().toUpperCase()+"-001";
var vulnerability = new Vulnerability();
Expand All @@ -70,6 +86,7 @@ public void shouldAuditVulnerabilityFromAllSourcesUsingVex() throws URISyntaxExc
audit.setAffects(List.of(affect));
audits.add(audit);
}
audits.addAll(vex.getVulnerabilities());
vex.setVulnerabilities(audits);
qm.getPersistenceManager().refreshAll();

Expand All @@ -79,8 +96,11 @@ public void shouldAuditVulnerabilityFromAllSourcesUsingVex() throws URISyntaxExc
// Assert
final Query<Analysis> query = qm.getPersistenceManager().newQuery(Analysis.class, "project == :project");
var analyses = (List<Analysis>) query.execute(project);
// CVE-2020-256[49|50] are not audited otherwise analyses.size would have been equal to sources.size()+2
Assert.assertEquals(sources.size(), analyses.size());
Assertions.assertThat(analyses).allSatisfy(analysis -> {
Assertions.assertThat(analysis.getVulnerability().getVulnId()).isNotEqualTo("CVE-2020-25649");
Assertions.assertThat(analysis.getVulnerability().getVulnId()).isNotEqualTo("CVE-2020-25650");
Assertions.assertThat(analysis.isSuppressed()).isTrue();
Assertions.assertThat(analysis.getAnalysisComments().size()).isEqualTo(3);
Assertions.assertThat(analysis.getAnalysisComments()).satisfiesExactlyInAnyOrder(comment -> {
Expand Down
54 changes: 53 additions & 1 deletion src/test/resources/vex-1.json
Expand Up @@ -20,6 +20,58 @@
}
},
"vulnerabilities": [

{
"id": "CVE-2020-25649",
"source": {
"name": "National Vulnerability Database",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-25649"
},
"ratings": [
{
"source": {
"name": "NVD",
"url": "https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N&version=3.1"
},
"score": 7.5,
"severity": "high",
"method": "CVSSv31",
"vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
}
],
"analysis": {
"state": "not_affected"
},
"affects": [
{
"ref": "7f2ee811-6b35-4c24-83ec-605d7939005c"
}
]
},
{
"id": "CVE-2020-25650",
"source": {
"name": "OSSINDEX",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-25650"
},
"ratings": [
{
"source": {
"name": "OSSINDEX"
},
"score": 7.5,
"severity": "high",
"method": "CVSSv31",
"vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
}
],
"analysis": {
"state": "false_positive"
},
"affects": [
{
"ref": "7f2ee811-6b35-4c24-83ec-605d7939005c"
}
]
}
]
}

0 comments on commit 4db8420

Please sign in to comment.