Skip to content

Commit dc2506f

Browse files
committed
Add CSV reader for Semgrep for CSV results downloaded from https://semgrep.dev/orgs/YOUR-personal-org/findings via "Download findings as CSV" button.
1 parent 12c593a commit dc2506f

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed

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.ContrastScanReader;
@@ -98,6 +99,7 @@ public static List<Reader> allReaders() {
9899
new ScnrReader(),
99100
new SeekerReader(),
100101
new SemgrepReader(),
102+
new SemgrepCSVReader(),
101103
new SemgrepSarifReader(),
102104
new ShiftLeftReader(),
103105
new ShiftLeftScanReader(),
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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 Sascha Knoop
16+
* @created 2024
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+
183+
tcr.setCategory(category);
184+
tcr.setCWE(cweLookup(category));
185+
tcr.setNumber(testNumber(filename));
186+
187+
return tcr;
188+
}
189+
190+
private int cweLookup(String category) {
191+
if (categoryMappings.containsKey(category)) {
192+
return categoryMappings.get(category);
193+
}
194+
195+
System.out.println(
196+
"WARNING: SemGrep CSV results file contained unmapped category: " + category);
197+
return CweNumber.DONTCARE;
198+
}
199+
}

0 commit comments

Comments
 (0)