Skip to content

Commit 1ec5221

Browse files
committed
Merge branch 'main' into generalizeScoring and resolve merge conflicts
2 parents e695029 + db7f69a commit 1ec5221

File tree

9 files changed

+234
-28
lines changed

9 files changed

+234
-28
lines changed

plugin/pom.xml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<dependency>
4848
<groupId>com.google.guava</groupId>
4949
<artifactId>guava</artifactId>
50-
<version>33.4.6-jre</version>
50+
<version>33.4.8-jre</version>
5151
</dependency>
5252

5353
<dependency>
@@ -65,7 +65,7 @@
6565
<dependency>
6666
<groupId>commons-io</groupId>
6767
<artifactId>commons-io</artifactId>
68-
<version>2.18.0</version>
68+
<version>2.19.0</version>
6969
</dependency>
7070

7171
<dependency>
@@ -89,7 +89,7 @@
8989
<dependency>
9090
<groupId>org.apache.httpcomponents.client5</groupId>
9191
<artifactId>httpclient5</artifactId>
92-
<version>5.4.3</version>
92+
<version>5.5</version>
9393
</dependency>
9494

9595
<dependency>
@@ -128,13 +128,13 @@
128128
<dependency>
129129
<groupId>org.jfree</groupId>
130130
<artifactId>jfreechart</artifactId>
131-
<version>1.5.5</version>
131+
<version>1.5.6</version>
132132
</dependency>
133133

134134
<dependency>
135135
<groupId>org.json</groupId>
136136
<artifactId>json</artifactId>
137-
<version>20250107</version>
137+
<version>20250517</version>
138138
</dependency>
139139

140140
<dependency>
@@ -192,10 +192,10 @@
192192
</build>
193193

194194
<properties>
195-
<version.fasterxml.jackson>2.18.3</version.fasterxml.jackson>
195+
<version.fasterxml.jackson>2.19.0</version.fasterxml.jackson>
196196
<!-- 3.0.3+ version of eclipse.persistence requires jakarta.xml.bind instead of jaxb -->
197197
<version.eclipse.persistence>2.7.15</version.eclipse.persistence>
198-
<version.junit.jupiter>5.12.1</version.junit.jupiter>
198+
<version.junit.jupiter>5.12.2</version.junit.jupiter>
199199
</properties>
200200

201201
</project>

plugin/src/main/java/org/owasp/benchmarkutils/score/ResultFile.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ private static CSVParser csvRecords(String content) {
147147
.setHeader()
148148
.setSkipHeaderRecord(false)
149149
.setIgnoreEmptyLines(false)
150-
.build()
150+
.setTrim(true) // trim leading/trailing blanks in column values
151+
.get()
151152
.parse(new StringReader(content));
152153
} catch (IOException e) {
153154
throw new RuntimeException(e);

plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/KlocworkCSVReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public TestSuiteResults parse(ResultFile resultFile) throws Exception {
5656
String header = inReader.readLine();
5757
CSVFormat.Builder CSVBuilder = CSVFormat.Builder.create(CSVFormat.RFC4180);
5858
CSVBuilder.setHeader(header.split(","));
59-
Iterable<CSVRecord> records = CSVBuilder.build().parse(inReader);
59+
Iterable<CSVRecord> records = CSVBuilder.get().parse(inReader);
6060

6161
for (CSVRecord record : records) {
6262
String category = record.get("Code"); // e.g., RLK.SQLOBJ

plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.owasp.benchmarkutils.score.BenchmarkScore;
2929
import org.owasp.benchmarkutils.score.ResultFile;
3030
import org.owasp.benchmarkutils.score.TestSuiteResults;
31+
import org.owasp.benchmarkutils.score.parsers.csv.SemgrepCSVReader;
3132
import org.owasp.benchmarkutils.score.parsers.csv.WhiteHatDynamicReader;
3233
import org.owasp.benchmarkutils.score.parsers.sarif.CodeQLReader;
3334
import org.owasp.benchmarkutils.score.parsers.sarif.CodeSonarReader;
@@ -103,6 +104,7 @@ public static List<Reader> allReaders() {
103104
new ScnrReader(),
104105
new SeekerReader(),
105106
new SemgrepReader(),
107+
new SemgrepCSVReader(),
106108
new SemgrepSarifReader(),
107109
new ShiftLeftReader(),
108110
new ShiftLeftScanReader(),

plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/ReshiftReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public TestSuiteResults parse(ResultFile resultFile) throws Exception {
103103

104104
CSVFormat.Builder CSVBuilder = CSVFormat.Builder.create(CSVFormat.RFC4180);
105105
CSVBuilder.setHeader(header.split(","));
106-
Iterable<CSVRecord> records = CSVBuilder.build().parse(inReader);
106+
Iterable<CSVRecord> records = CSVBuilder.get().parse(inReader);
107107

108108
for (CSVRecord record : records) {
109109
String url = record.get("Issue-File");
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/**
2+
* OWASP Benchmark Project
3+
*
4+
* <p>This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For
5+
* details, please see <a
6+
* href="https://owasp.org/www-project-benchmark/">https://owasp.org/www-project-benchmark/</a>.
7+
*
8+
* <p>The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms
9+
* of the GNU General Public License as published by the Free Software Foundation, version 2.
10+
*
11+
* <p>The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY
12+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13+
* PURPOSE. See the GNU General Public License for more details
14+
*
15+
* @author Dave Wichers
16+
* @created 2025
17+
*/
18+
package org.owasp.benchmarkutils.score.parsers.csv;
19+
20+
import java.util.HashMap;
21+
import java.util.List;
22+
import java.util.Map;
23+
import org.apache.commons.csv.CSVParser;
24+
import org.apache.commons.csv.CSVRecord;
25+
import org.owasp.benchmarkutils.score.BenchmarkScore;
26+
import org.owasp.benchmarkutils.score.CweNumber;
27+
import org.owasp.benchmarkutils.score.ResultFile;
28+
import org.owasp.benchmarkutils.score.TestCaseResult;
29+
import org.owasp.benchmarkutils.score.TestSuiteResults;
30+
import org.owasp.benchmarkutils.score.parsers.Reader;
31+
32+
/**
33+
* Reader for <a href="https://semgrep.dev/orgs/YOUR_org/findings">SemGrep</a> results downloaded
34+
* via: "Download findings as CSV" button, next to Sort menu.
35+
*/
36+
public class SemgrepCSVReader extends Reader {
37+
38+
private final Map<String, Integer> categoryMappings = new HashMap<>();
39+
40+
// Mapping/explanation of SemGrep rules can be found here, for example:
41+
// https://semgrep.dev/r?q=java.servlets.security.tainted-cmd-from-http-request.tainted-cmd-from-http-request
42+
public SemgrepCSVReader() {
43+
categoryMappings.put(
44+
"java.lang.security.audit.active-debug-code-printstacktrace.active-debug-code-printstacktrace",
45+
209); // CWE-209: Generation of Error Message Containing Sensitive Information
46+
categoryMappings.put(
47+
"java.servlets.security.tainted-cmd-from-http-request.tainted-cmd-from-http-request",
48+
CweNumber.COMMAND_INJECTION);
49+
categoryMappings.put(
50+
"java.lang.security.audit.command-injection-process-builder.command-injection-process-builder",
51+
CweNumber.COMMAND_INJECTION);
52+
categoryMappings.put(
53+
"java.lang.security.audit.tainted-cmd-from-http-request.tainted-cmd-from-http-request",
54+
CweNumber.COMMAND_INJECTION);
55+
categoryMappings.put(
56+
"java.servlets.security.tainted-cmd-from-http-request-deepsemgrep.tainted-cmd-from-http-request-deepsemgrep",
57+
CweNumber.COMMAND_INJECTION);
58+
categoryMappings.put(
59+
"python.django.security.django-no-csrf-token.django-no-csrf-token", CweNumber.CSRF);
60+
categoryMappings.put(
61+
"java.lang.security.httpservlet-path-traversal.httpservlet-path-traversal",
62+
CweNumber.PATH_TRAVERSAL);
63+
categoryMappings.put(
64+
"java.servlets.security.httpservlet-path-traversal-deepsemgrep.httpservlet-path-traversal-deepsemgrep",
65+
CweNumber.PATH_TRAVERSAL);
66+
categoryMappings.put(
67+
"java.servlets.security.httpservlet-path-traversal.httpservlet-path-traversal",
68+
CweNumber.PATH_TRAVERSAL);
69+
categoryMappings.put(
70+
"java.lang.security.audit.tainted-ldapi-from-http-request.tainted-ldapi-from-http-request",
71+
CweNumber.LDAP_INJECTION);
72+
categoryMappings.put(
73+
"java.servlets.security.tainted-ldapi-from-http-request.tainted-ldapi-from-http-request",
74+
CweNumber.LDAP_INJECTION);
75+
categoryMappings.put(
76+
"java.servlets.security.tainted-ldapi-from-http-request-deepsemgrep.tainted-ldapi-from-http-request-deepsemgrep",
77+
CweNumber.LDAP_INJECTION);
78+
categoryMappings.put(
79+
"java.lang.security.audit.sqli.jdbc-sqli.jdbc-sqli", CweNumber.SQL_INJECTION);
80+
categoryMappings.put(
81+
"java.lang.security.audit.sqli.tainted-sql-from-http-request.tainted-sql-from-http-request",
82+
CweNumber.SQL_INJECTION);
83+
categoryMappings.put(
84+
"java.lang.security.audit.tainted-session-from-http-request.tainted-session-from-http-request",
85+
CweNumber.TRUST_BOUNDARY_VIOLATION);
86+
categoryMappings.put(
87+
"java.servlets.security.tainted-session-from-http-request.tainted-session-from-http-request",
88+
CweNumber.TRUST_BOUNDARY_VIOLATION);
89+
categoryMappings.put(
90+
"java.servlets.security.tainted-session-from-http-request-deepsemgrep.tainted-session-from-http-request-deepsemgrep",
91+
CweNumber.TRUST_BOUNDARY_VIOLATION);
92+
categoryMappings.put(
93+
"java.lang.security.audit.tainted-xpath-from-http-request.tainted-xpath-from-http-request",
94+
CweNumber.XPATH_INJECTION);
95+
categoryMappings.put(
96+
"java.servlets.security.tainted-xpath-from-http-request.tainted-xpath-from-http-request",
97+
CweNumber.XPATH_INJECTION);
98+
categoryMappings.put(
99+
"java.servlets.security.tainted-xpath-from-http-request-deepsemgrep.tainted-xpath-from-http-request-deepsemgrep",
100+
CweNumber.XPATH_INJECTION);
101+
categoryMappings.put(
102+
"java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer",
103+
CweNumber.XSS);
104+
categoryMappings.put(
105+
"java.servlets.security.servletresponse-writer-xss.servletresponse-writer-xss",
106+
CweNumber.XSS);
107+
categoryMappings.put(
108+
"java.servlets.security.servletresponse-writer-xss-deepsemgrep.servletresponse-writer-xss-deepsemgrep",
109+
CweNumber.XSS);
110+
categoryMappings.put(
111+
"java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly",
112+
CweNumber.COOKIE_WITHOUT_HTTPONLY);
113+
categoryMappings.put(
114+
"java.servlets.security.audit.cookie-missing-httponly.cookie-missing-httponly",
115+
CweNumber.COOKIE_WITHOUT_HTTPONLY);
116+
categoryMappings.put(
117+
"java.lang.security.audit.cookie-missing-secure-flag.cookie-missing-secure-flag",
118+
CweNumber.INSECURE_COOKIE);
119+
categoryMappings.put(
120+
"java.servlets.security.audit.cookie-secure-flag-false.cookie-secure-flag-false",
121+
CweNumber.INSECURE_COOKIE);
122+
categoryMappings.put(
123+
"java.servlets.security.audit.cookie-missing-samesite.cookie-missing-samesite",
124+
1275); // CWE-1275: Sensitive Cookie with Improper SameSite Attribute
125+
categoryMappings.put(
126+
"java.lang.security.audit.crypto.des-is-deprecated.des-is-deprecated",
127+
CweNumber.WEAK_CRYPTO_ALGO);
128+
categoryMappings.put(
129+
"java.lang.security.audit.crypto.desede-is-deprecated.desede-is-deprecated",
130+
CweNumber.WEAK_CRYPTO_ALGO);
131+
categoryMappings.put(
132+
"java.lang.security.audit.crypto.use-of-md5.use-of-md5", CweNumber.WEAK_HASH_ALGO);
133+
categoryMappings.put(
134+
"java.lang.security.audit.crypto.use-of-sha1.use-of-sha1",
135+
CweNumber.WEAK_HASH_ALGO);
136+
categoryMappings.put(
137+
"java.lang.security.audit.crypto.weak-random.weak-random", CweNumber.WEAK_RANDOM);
138+
}
139+
140+
@Override
141+
public boolean canRead(ResultFile resultFile) {
142+
return resultFile.filename().endsWith(".csv")
143+
&& resultFile.line(0).contains("Semgrep Platform Link");
144+
}
145+
146+
@Override
147+
public TestSuiteResults parse(ResultFile resultFile) throws Exception {
148+
TestSuiteResults tr =
149+
new TestSuiteResults("Semgrep", false, TestSuiteResults.ToolType.SAST);
150+
151+
try (CSVParser records = resultFile.csvRecordsSkipFirstRows(headerRow(resultFile))) {
152+
records.stream()
153+
.filter(SemgrepCSVReader::isRelevant)
154+
.forEach(r -> tr.put(toTestCaseResult(r)));
155+
}
156+
157+
return tr;
158+
}
159+
160+
private int headerRow(ResultFile resultFile) {
161+
List<String> rows = resultFile.contentAsRows();
162+
163+
for (int i = 0; i < rows.size(); i++) {
164+
if (rows.get(i).startsWith("Id")) {
165+
return i;
166+
}
167+
}
168+
169+
throw new RuntimeException("No header row found");
170+
}
171+
172+
private static boolean isRelevant(CSVRecord r) {
173+
return extractFilenameWithoutEnding(r.get("Line Of Code Url"))
174+
.startsWith(BenchmarkScore.TESTCASENAME);
175+
}
176+
177+
private TestCaseResult toTestCaseResult(CSVRecord record) {
178+
String filename = record.get("Line Of Code Url");
179+
String category = record.get("Rule Name");
180+
181+
TestCaseResult tcr = new TestCaseResult();
182+
tcr.setActualResultTestID(filename);
183+
tcr.setCWE(cweLookup(category));
184+
185+
return tcr;
186+
}
187+
188+
private int cweLookup(String category) {
189+
if (categoryMappings.containsKey(category)) {
190+
return categoryMappings.get(category);
191+
}
192+
193+
System.out.println(
194+
"WARNING: SemGrep CSV results file contained unmapped category: " + category);
195+
return CweNumber.DONTCARE;
196+
}
197+
}

plugin/src/main/java/org/owasp/benchmarkutils/score/service/ExpectedResultsProvider.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,17 @@
3434

3535
public class ExpectedResultsProvider {
3636

37-
private static final String PREFIX = " version: ";
37+
// The following are column titles or elements in the expected results file
38+
public static final String PREFIX = " version: ";
3839

39-
private static final String TEST_NAME = "# test name";
40-
// private static final String CATEGORY = " category";
41-
private static final String REAL_VULNERABILITY = " real vulnerability";
42-
private static final String CWE = " cwe";
40+
public static final String TEST_NAME = "# test name";
41+
public static final String CATEGORY = "category";
42+
public static final String REAL_VULNERABILITY = "real vulnerability";
43+
public static final String CWE = "cwe";
4344

44-
private static final String SOURCE = " source";
45-
private static final String DATA_FLOW = " data flow";
46-
private static final String SINK = " sink";
45+
public static final String SOURCE = "source";
46+
public static final String DATA_FLOW = "data flow";
47+
public static final String SINK = "sink";
4748

4849
private static boolean standardBenchmarkStyleScoring;
4950
private static TestSuiteResults expectedResults;
@@ -65,11 +66,14 @@ public static TestSuiteResults parse(ResultFile resultFile) throws IOException {
6566
for (CSVRecord record : allExpectedResults) {
6667
TestCaseResult tcr = new TestCaseResult();
6768

68-
String testCaseFileName = record.get(TEST_NAME).trim();
69+
String testCaseFileName = record.get(TEST_NAME);
6970
tcr.setTestCaseName(testCaseFileName);
70-
tcr.setTruePositive(parseBoolean(record.get(REAL_VULNERABILITY).trim()));
71-
int cwe = parseInt(record.get(CWE).trim());
71+
// tcr.setCategory(record.get(CATEGORY));
72+
tcr.setTruePositive(parseBoolean(record.get(REAL_VULNERABILITY)));
73+
int cwe = parseInt(record.get(CWE));
7274
tcr.setCWE(cwe);
75+
// tcr.setNumber(testNumber(record.get(TEST_NAME), testCaseName));
76+
7377
if (TestCaseResult.UNMAPPED_CATEGORY.equals(tcr.getCategory())) {
7478
System.out.println(
7579
"FATAL ERROR: CWE metadata missing for CWE: "

plugin/src/main/java/org/owasp/benchmarkutils/tools/CalculateToolCodeBlocksSupport.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.owasp.benchmarkutils.score.TestCaseResult;
4646
import org.owasp.benchmarkutils.score.TestSuiteResults;
4747
import org.owasp.benchmarkutils.score.TestSuiteResults.ToolType;
48+
import org.owasp.benchmarkutils.score.service.ExpectedResultsProvider;
4849
import org.w3c.dom.Element;
4950

5051
@Mojo(
@@ -237,12 +238,13 @@ protected void run() {
237238
TestCaseResult theResult = new TestCaseResult(theTestcases.get(i));
238239

239240
// Get whether this test case is a true or false positive and set that
240-
String truePositive = records.get(i).get(" real vulnerability").trim();
241+
String truePositive =
242+
records.get(i).get(ExpectedResultsProvider.REAL_VULNERABILITY);
241243
theResult.setTruePositive(Boolean.parseBoolean(truePositive));
242244

243245
// Get whether the tool passed/failed this test case and set that result
244-
String passFail = records.get(i).get(" pass/fail").trim();
245-
theResult.setPassed("pass".equals(passFail));
246+
String passFail = records.get(i).get("pass/fail");
247+
theResult.setPassed(passFail.equals("pass"));
246248

247249
// While we are spinning through all the test cases, populate the lists of the
248250
// sources, dataflows, and sinks.
@@ -338,7 +340,7 @@ protected void run() {
338340
+ sinkCodeBlockFilename.replace(".code", ".xml"));
339341
if (sinkMetaDataFile.exists()) {
340342
// For sinks, we also add the vuln category to the CodeBlockSupportResults
341-
String vulnCategory = records.get(i).get(" category").trim();
343+
String vulnCategory = records.get(i).get(ExpectedResultsProvider.CATEGORY);
342344

343345
Element emetadata =
344346
CodeblockUtils.getSinkElementFromXMLFile(sinkMetaDataFile);

0 commit comments

Comments
 (0)