Skip to content

Commit

Permalink
Ignore advisories from GHSA that are withdrawn.
Browse files Browse the repository at this point in the history
  • Loading branch information
MagielBruntink committed Jan 25, 2024
1 parent eab1a55 commit 071215b
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public static class GHPageInfo {

public static class GHAdvisory {
public String description;
public String withdrawnAt;
public List<GHIdentifiers> identifiers;
public Severity severity;
public GHCVSS cvss;
Expand All @@ -106,6 +107,10 @@ public void setDescription(String description) {
this.description = description;
}

public String getWithdrawnAt() { return withdrawnAt; }

public void setWithdrawnAt(String withdrawnAt ) { this.withdrawnAt = withdrawnAt; }

public List<GHIdentifiers> getIdentifiers() {
return identifiers;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public String buildQuery(String cursor) {
" references {\n" +
" url\n" +
" }\n" +
" withdrawnAt\n" +
" vulnerabilities(first: 10) {\n" +
" nodes {\n" +
" package {\n" +
Expand Down Expand Up @@ -151,43 +152,48 @@ public String buildQuery(String cursor) {
public void parseGHResponse(JSONHandler.GHResponse response, HashMap<String, Vulnerability> vulnerabilities) {
for (JSONHandler.GHAdvisory advisory : response.getData().getSecurityAdvisories().getNodes()) {
logger.info("Parsing information of Vulnerability with ID - " + advisory.getAdvisoryId());
var v = new Vulnerability(advisory.getAdvisoryId());
v.setSeverity(advisory.getSeverity());
v.setDescription(advisory.getDescription());
advisory.getReferences().forEach(ref -> v.addReference(ref.getUrl()));
extractCweIds(v, advisory);
if(advisory.getWithdrawnAt() != null) {
logger.info("Vulnerability with ID was withdrawn at " + advisory.getWithdrawnAt() + " , skipping.");
}
else {
var v = new Vulnerability(advisory.getAdvisoryId());
v.setSeverity(advisory.getSeverity());
v.setDescription(advisory.getDescription());
advisory.getReferences().forEach(ref -> v.addReference(ref.getUrl()));
extractCweIds(v, advisory);

for (JSONHandler.GHNodes node : advisory.getVulnerabilities().getNodes()) {
var ecosystem = node.ghPackage.ecosystem;
String pgkIdentifier = null;
if (ecosystem.equals("PIP")) {
pgkIdentifier = "pkg:pypi/" + node.getGhPackage().name;
}
if (ecosystem.equals("MAVEN")) {
var coordinates = node.getGhPackage().getName().split(":");
if (coordinates.length > 1) {
pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + coordinates[1];
} else {
String[] splits = coordinates[0].split("\\.");
pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + splits[splits.length - 1];
for (JSONHandler.GHNodes node : advisory.getVulnerabilities().getNodes()) {
var ecosystem = node.ghPackage.ecosystem;
String pgkIdentifier = null;
if (ecosystem.equals("PIP")) {
pgkIdentifier = "pkg:pypi/" + node.getGhPackage().name;
}
}
if (pgkIdentifier != null) {
List<String> allVersions = versionRanger.getVersions(pgkIdentifier);
if (allVersions != null) {
var vulnerableVersions = versionRanger.getVulnerableVersionsJSON(node.vulnerableVersionRange, allVersions);
for (String version : vulnerableVersions) {
v.addPurl(pgkIdentifier + "@" + version);
if (ecosystem.equals("MAVEN")) {
var coordinates = node.getGhPackage().getName().split(":");
if (coordinates.length > 1) {
pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + coordinates[1];
} else {
String[] splits = coordinates[0].split("\\.");
pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + splits[splits.length - 1];
}
}
if (pgkIdentifier != null) {
List<String> allVersions = versionRanger.getVersions(pgkIdentifier);
if (allVersions != null) {
var vulnerableVersions = versionRanger.getVulnerableVersionsJSON(node.vulnerableVersionRange, allVersions);
for (String version : vulnerableVersions) {
v.addPurl(pgkIdentifier + "@" + version);
}
}

if (node.firstPatchedVersion != null)
v.addFirstPatchedPurl(pgkIdentifier + "@" + node.firstPatchedVersion.identifier);
if (node.firstPatchedVersion != null)
v.addFirstPatchedPurl(pgkIdentifier + "@" + node.firstPatchedVersion.identifier);
}
}
// Add the vulnerability to the Hash Map
vulnerabilities.put(v.getId(), v);
storeAdvisory(advisory);
}
// Add the vulnerability to the Hash Map
vulnerabilities.put(v.getId(), v);
storeAdvisory(advisory);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class GHParserTest {
" references {\n" +
" url\n" +
" }\n" +
" withdrawnAt\n" +
" vulnerabilities(first: 10) {\n" +
" nodes {\n" +
" package {\n" +
Expand Down Expand Up @@ -111,6 +112,7 @@ public class GHParserTest {
" references {\n" +
" url\n" +
" }\n" +
" withdrawnAt\n" +
" vulnerabilities(first: 10) {\n" +
" nodes {\n" +
" package {\n" +
Expand Down Expand Up @@ -141,6 +143,16 @@ public class GHParserTest {
}
}

String ghResponseAPIWithdrawn;

{
try {
ghResponseAPIWithdrawn = FileUtils.readFileToString(new File("./src/test/resources/parsers/ghAPISecurityWithdrawn.json"), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void testQueryBuilder() {
String queryWithoutCursor = ghParser.buildQuery(null);
Expand Down Expand Up @@ -173,12 +185,25 @@ public void testParseGHResponse() throws Exception {
"unmarshalling, leading to a remote application crash, as demonstrated by an" +
" xstream.fromXML(\"<void/>\") call.");


// ASSERT
assertEquals(1, result.size());
assertEquals(vCheck, result.get("CVE-2017-7957"));
}

@Test
public void testParseGHResponseWithdrawn() throws Exception {
HashMap<String, String> values = new HashMap<>();
values.put("query", queryNoCursor);
when(clientMock.sendPost("https://api.github.com/graphql", token, values)).thenReturn(ghResponseAPIWithdrawn);
var versions = Stream.of("1.3.2", "1.4.9", "1.4.10", "1.4.12").map(x -> new ImmutablePair<>(x, new DateTime())).collect(Collectors.toList());
ghParser.getVersionRanger().versionsMappings.put("pkg:maven/com.thoughtworks.xstream/xstream", versions);
ghParser.setCursor(null);

HashMap<String, Vulnerability> result = ghParser.getVulnerabilities(false);

assertEquals(0, result.size());
}

@AfterAll
public static void deleteCursor() {
File ghCursor = new File("./src/test/resources/parsers/cursor.txt.txt");
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/parsers/ghAPISecurity.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"url": "https://github.com/advisories/GHSA-7hwc-46rm-65jh"
}
],
"withdrawnAt" : null,
"vulnerabilities": {
"nodes": [
{
Expand Down
46 changes: 46 additions & 0 deletions src/test/resources/parsers/ghAPISecurityWithdrawn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"data": {
"securityAdvisories": {
"nodes": [
{
"description": "XStream through 1.4.9, when a certain denyTypes workaround is not used, mishandles attempts to create an instance of the primitive type 'void' during unmarshalling, leading to a remote application crash, as demonstrated by an xstream.fromXML(\"<void/>\") call.",
"identifiers": [
{
"type": "GHSA",
"value": "GHSA-7hwc-46rm-65jh"
},
{
"type": "CVE",
"value": "CVE-2017-7957"
}
],
"severity": "HIGH",
"references": [
{
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-7957"
},
{
"url": "https://github.com/advisories/GHSA-7hwc-46rm-65jh"
}
],
"withdrawnAt" : "placeholder date",
"vulnerabilities": {
"nodes": [
{
"package": {
"ecosystem": "MAVEN",
"name": "com.thoughtworks.xstream:xstream"
},
"vulnerableVersionRange": "< 1.4.10"
}
]
}
}
],
"pageInfo": {
"endCursor": "Y3Vyc29yOnYyOpK5MjAyMC0wNi0wNFQwMDowMjoxOSswMjowMM0ITw==",
"hasNextPage": false
}
}
}
}

0 comments on commit 071215b

Please sign in to comment.