High | DOM Based Cross-Site Scripting |
CWE-79
|
stored-xss.js:40
| 1 | 2025-10-17 06:27pm |
Vulnerable Code
|
$.get('CrossSiteScripting/stored-xss', function (result, status) { |
|
for (var i = 0; i < result.length; i++) { |
|
var comment = html.replace('USER', result[i].user); |
|
comment = comment.replace('DATETIME', result[i].dateTime); |
|
comment = comment.replace('COMMENT', result[i].text); |
|
$("#list").append(comment); |
1 Data Flow/s detected
|
$.get('CrossSiteScripting/stored-xss', function (result, status) { |
|
comment = comment.replace('COMMENT', result[i].text); |
|
$("#list").append(comment); |
Remediation Suggestion
|
+var escape = require('escape-html'); |
|
$(document).ready(function () { |
|
$("#postComment").on("click", function () { |
|
var commentInput = $("#commentInput").val(); |
|
$.ajax({ |
|
type: 'POST', |
|
url: 'CrossSiteScripting/stored-xss', |
|
data: JSON.stringify({text: commentInput}), |
|
contentType: "application/json", |
|
dataType: 'json' |
|
}).then( |
|
function () { |
|
getChallenges(); |
|
$("#commentInput").val(''); |
|
} |
|
) |
|
}) |
|
|
|
var html = '<li class="comment">' + |
|
'<div class="pull-left">' + |
|
'<img class="avatar" src="images/avatar1.png" alt="avatar"/>' + |
|
'</div>' + |
|
'<div class="comment-body">' + |
|
'<div class="comment-heading">' + |
|
'<h4 class="user">USER</h4>' + |
|
'<h5 class="time">DATETIME</h5>' + |
|
'</div>' + |
|
'<p>COMMENT</p>' + |
|
'</div>' + |
|
'</li>'; |
|
|
|
getChallenges(); |
|
|
|
function getChallenges() { |
|
$("#list").empty(); |
|
$.get('CrossSiteScripting/stored-xss', function (result, status) { |
|
for (var i = 0; i < result.length; i++) { |
|
- var comment = html.replace('USER', result[i].user); |
|
- comment = comment.replace('DATETIME', result[i].dateTime); |
|
- comment = comment.replace('COMMENT', result[i].text); |
|
+ var comment = html.replace('USER', escape(result[i].user)); |
|
+ comment = comment.replace('DATETIME', escape(result[i].dateTime)); |
|
+ comment = comment.replace('COMMENT', escape(result[i].text)); |
|
$("#list").append(comment); |
|
} |
|
|
|
}); |
|
} |
|
}) |
✔️ Pull request created
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | SQL Injection |
CWE-89
|
SqlInjectionLesson8.java:158
| 2 | 2025-06-30 02:46pm |
Vulnerable Code
|
String logQuery = |
|
"INSERT INTO access_log (time, action) VALUES ('" + time + "', '" + action + "')"; |
|
|
|
try { |
|
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); |
|
statement.executeUpdate(logQuery); |
2 Data Flow/s detected
View Data Flow 1
|
public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { |
|
return injectableQueryConfidentiality(name, auth_tan); |
|
protected AttackResult injectableQueryConfidentiality(String name, String auth_tan) { |
|
"SELECT * FROM employees WHERE last_name = '" |
|
public static void log(Connection connection, String action) { |
|
action = action.replace('\'', '"'); |
|
"INSERT INTO access_log (time, action) VALUES ('" + time + "', '" + action + "')"; |
|
statement.executeUpdate(logQuery); |
View Data Flow 2
|
public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { |
|
return injectableQueryIntegrity(name, auth_tan); |
|
protected AttackResult injectableQueryIntegrity(String name, String auth_tan) { |
|
"SELECT * FROM employees WHERE last_name = '" |
|
SqlInjectionLesson8.log(connection, query); |
|
public static void log(Connection connection, String action) { |
|
action = action.replace('\'', '"'); |
|
"INSERT INTO access_log (time, action) VALUES ('" + time + "', '" + action + "')"; |
|
statement.executeUpdate(logQuery); |
Remediation Suggestion
|
/* |
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ |
|
* |
|
* Copyright (c) 2002 - 2019 Bruce Mayhew |
|
* |
|
* This program is free software; you can redistribute it and/or modify it under the terms of the |
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the |
|
* License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without |
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
* General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License along with this program; if |
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
|
* 02111-1307, USA. |
|
* |
|
* Getting Source ============== |
|
* |
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. |
|
*/ |
|
|
|
package org.owasp.webgoat.lessons.sqlinjection.introduction; |
|
|
|
+import java.sql.PreparedStatement; |
|
import static java.sql.ResultSet.CONCUR_UPDATABLE; |
|
import static java.sql.ResultSet.TYPE_SCROLL_SENSITIVE; |
|
|
|
import java.sql.*; |
|
import java.text.SimpleDateFormat; |
|
import java.util.Calendar; |
|
import org.owasp.webgoat.container.LessonDataSource; |
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint; |
|
import org.owasp.webgoat.container.assignments.AssignmentHints; |
|
import org.owasp.webgoat.container.assignments.AttackResult; |
|
import org.springframework.web.bind.annotation.PostMapping; |
|
import org.springframework.web.bind.annotation.RequestParam; |
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
import org.springframework.web.bind.annotation.RestController; |
|
|
|
@RestController |
|
@AssignmentHints( |
|
value = { |
|
"SqlStringInjectionHint.8.1", |
|
"SqlStringInjectionHint.8.2", |
|
"SqlStringInjectionHint.8.3", |
|
"SqlStringInjectionHint.8.4", |
|
"SqlStringInjectionHint.8.5" |
|
}) |
|
public class SqlInjectionLesson8 extends AssignmentEndpoint { |
|
|
|
private final LessonDataSource dataSource; |
|
|
|
public SqlInjectionLesson8(LessonDataSource dataSource) { |
|
this.dataSource = dataSource; |
|
} |
|
|
|
@PostMapping("/SqlInjection/attack8") |
|
@ResponseBody |
|
public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { |
|
return injectableQueryConfidentiality(name, auth_tan); |
|
} |
|
|
|
protected AttackResult injectableQueryConfidentiality(String name, String auth_tan) { |
|
StringBuilder output = new StringBuilder(); |
|
- String query = |
|
- "SELECT * FROM employees WHERE last_name = '" |
|
- + name |
|
- + "' AND auth_tan = '" |
|
- + auth_tan |
|
- + "'"; |
|
+ String query = "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?"; |
|
|
|
try (Connection connection = dataSource.getConnection()) { |
|
try { |
|
- Statement statement = |
|
- connection.createStatement( |
|
- ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); |
|
+ PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); |
|
+ statement.setString(1, name); |
|
+ statement.setString(2, auth_tan); |
|
log(connection, query); |
|
- ResultSet results = statement.executeQuery(query); |
|
+ ResultSet results = statement.executeQuery(); |
|
|
|
if (results.getStatement() != null) { |
|
if (results.first()) { |
|
output.append(generateTable(results)); |
|
results.last(); |
|
|
|
if (results.getRow() > 1) { |
|
// more than one record, the user succeeded |
|
return success(this) |
|
.feedback("sql-injection.8.success") |
|
.output(output.toString()) |
|
.build(); |
|
} else { |
|
// only one record |
|
return failed(this).feedback("sql-injection.8.one").output(output.toString()).build(); |
|
} |
|
|
|
} else { |
|
// no results |
|
return failed(this).feedback("sql-injection.8.no.results").build(); |
|
} |
|
} else { |
|
return failed(this).build(); |
|
} |
|
} catch (SQLException e) { |
|
return failed(this) |
|
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>") |
|
.build(); |
|
} |
|
|
|
} catch (Exception e) { |
|
return failed(this) |
|
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>") |
|
.build(); |
|
} |
|
} |
|
|
|
public static String generateTable(ResultSet results) throws SQLException { |
|
ResultSetMetaData resultsMetaData = results.getMetaData(); |
|
int numColumns = resultsMetaData.getColumnCount(); |
|
results.beforeFirst(); |
|
StringBuilder table = new StringBuilder(); |
|
table.append("<table>"); |
|
|
|
if (results.next()) { |
|
table.append("<tr>"); |
|
for (int i = 1; i < (numColumns + 1); i++) { |
|
table.append("<th>" + resultsMetaData.getColumnName(i) + "</th>"); |
|
} |
|
table.append("</tr>"); |
|
|
|
results.beforeFirst(); |
|
while (results.next()) { |
|
table.append("<tr>"); |
|
for (int i = 1; i < (numColumns + 1); i++) { |
|
table.append("<td>" + results.getString(i) + "</td>"); |
|
} |
|
table.append("</tr>"); |
|
} |
|
|
|
} else { |
|
table.append("Query Successful; however no data was returned from this query."); |
|
} |
|
|
|
table.append("</table>"); |
|
return (table.toString()); |
|
} |
|
|
|
public static void log(Connection connection, String action) { |
|
action = action.replace('\'', '"'); |
|
Calendar cal = Calendar.getInstance(); |
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|
String time = sdf.format(cal.getTime()); |
|
|
|
- String logQuery = |
|
- "INSERT INTO access_log (time, action) VALUES ('" + time + "', '" + action + "')"; |
|
+ String logQuery = "INSERT INTO access_log (time, action) VALUES (?, ?)"; |
|
|
|
try { |
|
- Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); |
|
- statement.executeUpdate(logQuery); |
|
+ PreparedStatement statement = connection.prepareStatement(logQuery, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); |
|
+ statement.setString(1, time); |
|
+ statement.setString(2, action); |
|
+ statement.executeUpdate(); |
|
} catch (SQLException e) { |
|
System.err.println(e.getMessage()); |
|
} |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | SQL Injection |
CWE-89
|
SqlInjectionLesson6a.java:74
| 3 | 2025-06-30 02:46pm |
Vulnerable Code
|
usedUnion = false; |
|
} |
|
try (Statement statement = |
|
connection.createStatement( |
|
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) { |
|
ResultSet results = statement.executeQuery(query); |
3 Data Flow/s detected
View Data Flow 1
|
public AttackResult completed(@RequestParam(value = "userid_6a") String userId) { |
|
return injectableQuery(userId); |
|
public AttackResult injectableQuery(String accountName) { |
|
query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; |
|
ResultSet results = statement.executeQuery(query); |
View Data Flow 2
|
public AttackResult attack(@RequestParam("userid_sql_only_input_validation") String userId) { |
|
AttackResult attackResult = lesson6a.injectableQuery(userId); |
|
public AttackResult injectableQuery(String accountName) { |
|
query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; |
|
ResultSet results = statement.executeQuery(query); |
View Data Flow 3
|
public AttackResult attack( |
|
userId = userId.toUpperCase().replace("FROM", "").replace("SELECT", ""); |
|
AttackResult attackResult = lesson6a.injectableQuery(userId); |
|
public AttackResult injectableQuery(String accountName) { |
|
query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; |
|
ResultSet results = statement.executeQuery(query); |
Remediation Suggestion
|
/* |
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ |
|
* |
|
* Copyright (c) 2002 - 2019 Bruce Mayhew |
|
* |
|
* This program is free software; you can redistribute it and/or modify it under the terms of the |
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the |
|
* License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without |
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
* General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License along with this program; if |
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
|
* 02111-1307, USA. |
|
* |
|
* Getting Source ============== |
|
* |
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. |
|
*/ |
|
|
|
package org.owasp.webgoat.lessons.sqlinjection.advanced; |
|
|
|
+import java.sql.PreparedStatement; |
|
import java.sql.*; |
|
import org.owasp.webgoat.container.LessonDataSource; |
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint; |
|
import org.owasp.webgoat.container.assignments.AssignmentHints; |
|
import org.owasp.webgoat.container.assignments.AttackResult; |
|
import org.owasp.webgoat.lessons.sqlinjection.introduction.SqlInjectionLesson5a; |
|
import org.springframework.web.bind.annotation.PostMapping; |
|
import org.springframework.web.bind.annotation.RequestParam; |
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
import org.springframework.web.bind.annotation.RestController; |
|
|
|
@RestController |
|
@AssignmentHints( |
|
value = { |
|
"SqlStringInjectionHint-advanced-6a-1", |
|
"SqlStringInjectionHint-advanced-6a-2", |
|
"SqlStringInjectionHint-advanced-6a-3", |
|
"SqlStringInjectionHint-advanced-6a-4", |
|
"SqlStringInjectionHint-advanced-6a-5" |
|
}) |
|
public class SqlInjectionLesson6a extends AssignmentEndpoint { |
|
|
|
private final LessonDataSource dataSource; |
|
private static final String YOUR_QUERY_WAS = "<br> Your query was: "; |
|
|
|
public SqlInjectionLesson6a(LessonDataSource dataSource) { |
|
this.dataSource = dataSource; |
|
} |
|
|
|
@PostMapping("/SqlInjectionAdvanced/attack6a") |
|
@ResponseBody |
|
public AttackResult completed(@RequestParam(value = "userid_6a") String userId) { |
|
return injectableQuery(userId); |
|
// The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from |
|
// user_system_data -- |
|
} |
|
|
|
public AttackResult injectableQuery(String accountName) { |
|
String query = ""; |
|
try (Connection connection = dataSource.getConnection()) { |
|
boolean usedUnion = true; |
|
- query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; |
|
- // Check if Union is used |
|
- if (!accountName.matches("(?i)(^[^-/*;)]*)(\\s*)UNION(.*$)")) { |
|
- usedUnion = false; |
|
- } |
|
- try (Statement statement = |
|
- connection.createStatement( |
|
- ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) { |
|
- ResultSet results = statement.executeQuery(query); |
|
+ query = "SELECT * FROM user_data WHERE last_name = ?"; |
|
+ try (PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) { |
|
+ statement.setString(1, accountName); |
|
+ ResultSet results = statement.executeQuery(); |
|
|
|
if ((results != null) && results.first()) { |
|
ResultSetMetaData resultsMetaData = results.getMetaData(); |
|
StringBuilder output = new StringBuilder(); |
|
|
|
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); |
|
|
|
String appendingWhenSucceded; |
|
if (usedUnion) |
|
appendingWhenSucceded = |
|
"Well done! Can you also figure out a solution, by appending a new SQL Statement?"; |
|
else |
|
appendingWhenSucceded = |
|
"Well done! Can you also figure out a solution, by using a UNION?"; |
|
results.last(); |
|
|
|
if (output.toString().contains("dave") && output.toString().contains("passW0rD")) { |
|
output.append(appendingWhenSucceded); |
|
return success(this) |
|
.feedback("sql-injection.advanced.6a.success") |
|
.feedbackArgs(output.toString()) |
|
.output(" Your query was: " + query) |
|
.build(); |
|
} else { |
|
return failed(this).output(output.toString() + YOUR_QUERY_WAS + query).build(); |
|
} |
|
} else { |
|
return failed(this) |
|
.feedback("sql-injection.advanced.6a.no.results") |
|
.output(YOUR_QUERY_WAS + query) |
|
.build(); |
|
} |
|
} catch (SQLException sqle) { |
|
return failed(this).output(sqle.getMessage() + YOUR_QUERY_WAS + query).build(); |
|
} |
|
} catch (Exception e) { |
|
return failed(this) |
|
.output(this.getClass().getName() + " : " + e.getMessage() + YOUR_QUERY_WAS + query) |
|
.build(); |
|
} |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | Path/Directory Traversal |
CWE-22
|
ProfileZipSlip.java:75
| 1 | 2025-06-30 02:46pm |
Vulnerable Code
|
Enumeration<? extends ZipEntry> entries = zip.entries(); |
|
while (entries.hasMoreElements()) { |
|
ZipEntry e = entries.nextElement(); |
|
File f = new File(tmpZipDirectory.toFile(), e.getName()); |
|
InputStream is = zip.getInputStream(e); |
|
Files.copy(is, f.toPath(), StandardCopyOption.REPLACE_EXISTING); |
1 Data Flow/s detected
|
File f = new File(tmpZipDirectory.toFile(), e.getName()); |
|
Files.copy(is, f.toPath(), StandardCopyOption.REPLACE_EXISTING); |
Remediation Suggestion
|
package org.owasp.webgoat.lessons.pathtraversal; |
|
|
|
+import java.nio.file.Paths; |
|
import static org.springframework.http.MediaType.ALL_VALUE; |
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; |
|
|
|
import java.io.File; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
import java.nio.file.Files; |
|
import java.nio.file.StandardCopyOption; |
|
import java.util.Arrays; |
|
import java.util.Enumeration; |
|
import java.util.zip.ZipEntry; |
|
import java.util.zip.ZipFile; |
|
import lombok.SneakyThrows; |
|
import lombok.extern.slf4j.Slf4j; |
|
import org.owasp.webgoat.container.assignments.AssignmentHints; |
|
import org.owasp.webgoat.container.assignments.AttackResult; |
|
import org.owasp.webgoat.container.session.WebSession; |
|
import org.springframework.beans.factory.annotation.Value; |
|
import org.springframework.http.ResponseEntity; |
|
import org.springframework.util.FileCopyUtils; |
|
import org.springframework.web.bind.annotation.GetMapping; |
|
import org.springframework.web.bind.annotation.PathVariable; |
|
import org.springframework.web.bind.annotation.PostMapping; |
|
import org.springframework.web.bind.annotation.RequestParam; |
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
import org.springframework.web.bind.annotation.RestController; |
|
import org.springframework.web.multipart.MultipartFile; |
|
|
|
@RestController |
|
@AssignmentHints({ |
|
"path-traversal-zip-slip.hint1", |
|
"path-traversal-zip-slip.hint2", |
|
"path-traversal-zip-slip.hint3", |
|
"path-traversal-zip-slip.hint4" |
|
}) |
|
@Slf4j |
|
public class ProfileZipSlip extends ProfileUploadBase { |
|
|
|
public ProfileZipSlip( |
|
@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { |
|
super(webGoatHomeDirectory, webSession); |
|
} |
|
|
|
@PostMapping( |
|
value = "/PathTraversal/zip-slip", |
|
consumes = ALL_VALUE, |
|
produces = APPLICATION_JSON_VALUE) |
|
@ResponseBody |
|
public AttackResult uploadFileHandler(@RequestParam("uploadedFileZipSlip") MultipartFile file) { |
|
if (!file.getOriginalFilename().toLowerCase().endsWith(".zip")) { |
|
return failed(this).feedback("path-traversal-zip-slip.no-zip").build(); |
|
} else { |
|
return processZipUpload(file); |
|
} |
|
} |
|
|
|
@SneakyThrows |
|
private AttackResult processZipUpload(MultipartFile file) { |
|
var tmpZipDirectory = Files.createTempDirectory(getWebSession().getUserName()); |
|
cleanupAndCreateDirectoryForUser(); |
|
var currentImage = getProfilePictureAsBase64(); |
|
|
|
try { |
|
var uploadedZipFile = tmpZipDirectory.resolve(file.getOriginalFilename()); |
|
FileCopyUtils.copy(file.getBytes(), uploadedZipFile.toFile()); |
|
|
|
ZipFile zip = new ZipFile(uploadedZipFile.toFile()); |
|
Enumeration<? extends ZipEntry> entries = zip.entries(); |
|
while (entries.hasMoreElements()) { |
|
ZipEntry e = entries.nextElement(); |
|
File f = new File(tmpZipDirectory.toFile(), e.getName()); |
|
+ String canonicalDestinationPath = f.getCanonicalPath(); |
|
+ String canonicalTmpZipDirectoryPath = tmpZipDirectory.toFile().getCanonicalPath(); |
|
+ if (!canonicalDestinationPath.startsWith(canonicalTmpZipDirectoryPath)) { |
|
+ throw new IOException("Entry is outside of the target dir: " + e.getName()); |
|
+ } |
|
+ |
|
InputStream is = zip.getInputStream(e); |
|
Files.copy(is, f.toPath(), StandardCopyOption.REPLACE_EXISTING); |
|
} |
|
|
|
return isSolved(currentImage, getProfilePictureAsBase64()); |
|
} catch (IOException e) { |
|
return failed(this).output(e.getMessage()).build(); |
|
} |
|
} |
|
|
|
private AttackResult isSolved(byte[] currentImage, byte[] newImage) { |
|
if (Arrays.equals(currentImage, newImage)) { |
|
return failed(this).output("path-traversal-zip-slip.extracted").build(); |
|
} |
|
return success(this).output("path-traversal-zip-slip.extracted").build(); |
|
} |
|
|
|
@GetMapping("/PathTraversal/zip-slip/") |
|
@ResponseBody |
|
public ResponseEntity<?> getProfilePicture() { |
|
return super.getProfilePicture(); |
|
} |
|
|
|
@GetMapping("/PathTraversal/zip-slip/profile-image/{username}") |
|
@ResponseBody |
|
public ResponseEntity<?> getProfilePicture(@PathVariable("username") String username) { |
|
return ResponseEntity.notFound().build(); |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior Path/Directory Traversal Training
Videos
Secure Code Warrior Path/Directory Traversal Video
Further Reading
OWASP Path Traversal
OWASP Input Validation Cheat Sheet
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | SQL Injection |
CWE-89
|
JWTFinalEndpoint.java:89
| 1 | 2026-06-23 05:02pm |
Vulnerable Code
|
final String kid = (String) header.get("kid"); |
|
try (var connection = dataSource.getConnection()) { |
|
ResultSet rs = |
|
connection |
|
.createStatement() |
|
.executeQuery( |
1 Data Flow/s detected
|
final String kid = (String) header.get("kid"); |
|
"SELECT key FROM jwt_keys WHERE id = '" + kid + "'"); |
Remediation Suggestion
|
/* |
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ |
|
* |
|
* Copyright (c) 2002 - 2019 Bruce Mayhew |
|
* |
|
* This program is free software; you can redistribute it and/or modify it under the terms of the |
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the |
|
* License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without |
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
* General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License along with this program; if |
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
|
* 02111-1307, USA. |
|
* |
|
* Getting Source ============== |
|
* |
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. |
|
*/ |
|
|
|
package org.owasp.webgoat.lessons.jwt; |
|
|
|
+import java.sql.PreparedStatement; |
|
import io.jsonwebtoken.Claims; |
|
import io.jsonwebtoken.JwsHeader; |
|
import io.jsonwebtoken.Jwt; |
|
import io.jsonwebtoken.JwtException; |
|
import io.jsonwebtoken.Jwts; |
|
import io.jsonwebtoken.SigningKeyResolverAdapter; |
|
import io.jsonwebtoken.impl.TextCodec; |
|
import java.sql.ResultSet; |
|
import java.sql.SQLException; |
|
import org.apache.commons.lang3.StringUtils; |
|
import org.owasp.webgoat.container.LessonDataSource; |
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint; |
|
import org.owasp.webgoat.container.assignments.AssignmentHints; |
|
import org.owasp.webgoat.container.assignments.AttackResult; |
|
import org.springframework.web.bind.annotation.PathVariable; |
|
import org.springframework.web.bind.annotation.PostMapping; |
|
import org.springframework.web.bind.annotation.RequestParam; |
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
import org.springframework.web.bind.annotation.RestController; |
|
|
|
@RestController |
|
@AssignmentHints({ |
|
"jwt-final-hint1", |
|
"jwt-final-hint2", |
|
"jwt-final-hint3", |
|
"jwt-final-hint4", |
|
"jwt-final-hint5", |
|
"jwt-final-hint6" |
|
}) |
|
public class JWTFinalEndpoint extends AssignmentEndpoint { |
|
|
|
private final LessonDataSource dataSource; |
|
|
|
private JWTFinalEndpoint(LessonDataSource dataSource) { |
|
this.dataSource = dataSource; |
|
} |
|
|
|
@PostMapping("/JWT/final/follow/{user}") |
|
public @ResponseBody String follow(@PathVariable("user") String user) { |
|
if ("Jerry".equals(user)) { |
|
return "Following yourself seems redundant"; |
|
} else { |
|
return "You are now following Tom"; |
|
} |
|
} |
|
|
|
@PostMapping("/JWT/final/delete") |
|
public @ResponseBody AttackResult resetVotes(@RequestParam("token") String token) { |
|
if (StringUtils.isEmpty(token)) { |
|
return failed(this).feedback("jwt-invalid-token").build(); |
|
} else { |
|
try { |
|
final String[] errorMessage = {null}; |
|
Jwt jwt = |
|
Jwts.parser() |
|
.setSigningKeyResolver( |
|
new SigningKeyResolverAdapter() { |
|
@Override |
|
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) { |
|
final String kid = (String) header.get("kid"); |
|
try (var connection = dataSource.getConnection()) { |
|
- ResultSet rs = |
|
- connection |
|
- .createStatement() |
|
- .executeQuery( |
|
- "SELECT key FROM jwt_keys WHERE id = '" + kid + "'"); |
|
+ String query = "SELECT key FROM jwt_keys WHERE id = ?"; |
|
+ try (PreparedStatement statement = connection.prepareStatement(query)) { |
|
+ statement.setString(1, kid); |
|
+ ResultSet rs = statement.executeQuery(); |
|
while (rs.next()) { |
|
return TextCodec.BASE64.decode(rs.getString(1)); |
|
} |
|
} catch (SQLException e) { |
|
errorMessage[0] = e.getMessage(); |
|
} |
|
return null; |
|
} |
|
}) |
|
.parseClaimsJws(token); |
|
if (errorMessage[0] != null) { |
|
return failed(this).output(errorMessage[0]).build(); |
|
} |
|
Claims claims = (Claims) jwt.getBody(); |
|
String username = (String) claims.get("username"); |
|
if ("Jerry".equals(username)) { |
|
return failed(this).feedback("jwt-final-jerry-account").build(); |
|
} |
|
if ("Tom".equals(username)) { |
|
return success(this).build(); |
|
} else { |
|
return failed(this).feedback("jwt-final-not-tom").build(); |
|
} |
|
} catch (JwtException e) { |
|
return failed(this).feedback("jwt-invalid-token").output(e.toString()).build(); |
|
} |
|
} |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | DOM Based Cross-Site Scripting |
CWE-79
|
jwt-voting.js:63
| 1 | 2025-10-17 06:27pm |
Vulnerable Code
|
var hidden = (result[i].numberOfVotes === undefined ? 'hidden' : ''); |
|
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_VOTES/g, hidden); |
|
hidden = (result[i].average === undefined ? 'hidden' : ''); |
|
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_RATING/g, hidden); |
|
|
|
$("#votesList").append(voteTemplate); |
1 Data Flow/s detected
|
$.get("JWT/votings", function (result, status) { |
|
voteTemplate = voteTemplate.replace('AVERAGE', result[i].average || ''); |
|
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_VOTES/g, hidden); |
|
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_RATING/g, hidden); |
|
$("#votesList").append(voteTemplate); |
Remediation Suggestion
|
+const DOMPurify = require('dompurify'); |
|
$(document).ready(function () { |
|
loginVotes('Guest'); |
|
}) |
|
|
|
function loginVotes(user) { |
|
$("#name").text(user); |
|
$.ajax({ |
|
url: 'JWT/votings/login?user=' + user, |
|
contentType: "application/json" |
|
}).always(function () { |
|
getVotings(); |
|
}) |
|
} |
|
|
|
var html = '<a href="#" class="list-group-item ACTIVE">' + |
|
'<div class="media col-md-3">' + |
|
'<figure> ' + |
|
'<img class="media-object img-rounded" src="images/IMAGE_SMALL" alt="placehold.it/350x250"/>' + |
|
'</figure>' + |
|
'</div> ' + |
|
'<div class="col-md-6">' + |
|
'<h4 class="list-group-item-heading">TITLE</h4>' + |
|
'<p class="list-group-item-text">INFORMATION</p>' + |
|
'</div>' + |
|
'<div class="col-md-3 text-center">' + |
|
'<h2 HIDDEN_VIEW_VOTES>NO_VOTES' + |
|
'<small HIDDEN_VIEW_VOTES> votes</small>' + |
|
'</h2>' + |
|
'<button type="button" id="TITLE" class="btn BUTTON btn-lg btn-block" onclick="vote(this.id)">Vote Now!</button>' + |
|
'<div style="visibility:HIDDEN_VIEW_RATING;" class="stars"> ' + |
|
'<span class="glyphicon glyphicon-star"></span>' + |
|
'<span class="glyphicon glyphicon-star"></span>' + |
|
'<span class="glyphicon glyphicon-star"></span>' + |
|
'<span class="glyphicon glyphicon-star-empty"></span>' + |
|
'</div>' + |
|
'<p HIDDEN_VIEW_RATING>Average AVERAGE<small> /</small>4</p>' + |
|
'</div>' + |
|
'<div class="clearfix"></div>' + |
|
'</a>'; |
|
|
|
function getVotings() { |
|
$("#votesList").empty(); |
|
$.get("JWT/votings", function (result, status) { |
|
for (var i = 0; i < result.length; i++) { |
|
var voteTemplate = html.replace('IMAGE_SMALL', result[i].imageSmall); |
|
if (i === 0) { |
|
voteTemplate = voteTemplate.replace('ACTIVE', 'active'); |
|
voteTemplate = voteTemplate.replace('BUTTON', 'btn-default'); |
|
} else { |
|
voteTemplate = voteTemplate.replace('ACTIVE', ''); |
|
voteTemplate = voteTemplate.replace('BUTTON', 'btn-primary'); |
|
} |
|
voteTemplate = voteTemplate.replace(/TITLE/g, result[i].title); |
|
voteTemplate = voteTemplate.replace('INFORMATION', result[i].information || ''); |
|
voteTemplate = voteTemplate.replace('NO_VOTES', result[i].numberOfVotes || ''); |
|
voteTemplate = voteTemplate.replace('AVERAGE', result[i].average || ''); |
|
|
|
var hidden = (result[i].numberOfVotes === undefined ? 'hidden' : ''); |
|
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_VOTES/g, hidden); |
|
hidden = (result[i].average === undefined ? 'hidden' : ''); |
|
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_RATING/g, hidden); |
|
+ voteTemplate = DOMPurify.sanitize(voteTemplate); |
|
|
|
$("#votesList").append(voteTemplate); |
|
} |
|
}) |
|
} |
|
|
|
webgoat.customjs.jwtSigningCallback = function () { |
|
getVotings(); |
|
} |
|
|
|
function vote(title) { |
|
var user = $("#name").text(); |
|
if (user === 'Guest') { |
|
alert("As a guest you are not allowed to vote, please login first.") |
|
} else { |
|
$.ajax({ |
|
type: 'POST', |
|
url: 'JWT/votings/' + title |
|
}).then( |
|
function () { |
|
getVotings(); |
|
} |
|
) |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | DOM Based Cross-Site Scripting |
CWE-79
|
xxe.js:78
| 1 | 2025-10-17 06:27pm |
Vulnerable Code
|
$(field).empty(); |
|
for (var i = 0; i < result.length; i++) { |
|
var comment = html.replace('USER', result[i].user); |
|
comment = comment.replace('DATETIME', result[i].dateTime); |
|
comment = comment.replace('COMMENT', result[i].text); |
|
$(field).append(comment); |
1 Data Flow/s detected
|
$.get("xxe/comments", function (result, status) { |
|
comment = comment.replace('COMMENT', result[i].text); |
|
$(field).append(comment); |
Remediation Suggestion
|
+ }); |
|
+ }[a]; |
|
+ '>': '>' |
|
+ '<': '<', |
|
+ "'": ''', |
|
+ '&': '&', |
|
+ '"': '"', |
|
+ return { |
|
+ return text.replace(/["&'<>]/g, function (a) { |
|
+function escapeHtml(text) { |
|
webgoat.customjs.simpleXXE = function () { |
|
var commentInput = $("#commentInputSimple").val(); |
|
var xml = '<?xml version="1.0"?>' + |
|
'<comment>' + |
|
' <text>' + commentInput + '</text>' + |
|
'</comment>'; |
|
return xml; |
|
} |
|
|
|
webgoat.customjs.simpleXXECallback = function() { |
|
$("#commentInputSimple").val(''); |
|
getComments('#commentsListSimple'); |
|
} |
|
|
|
$(document).ready(function () { |
|
getComments('#commentsListSimple'); |
|
}); |
|
|
|
//// Content-type |
|
|
|
webgoat.customjs.contentTypeXXE = function() { |
|
var commentInput = $("#commentInputContentType").val(); |
|
return JSON.stringify({text: commentInput}); |
|
} |
|
|
|
webgoat.customjs.contentTypeXXECallback = function() { |
|
$("#commentInputContentType").val(''); |
|
getComments('#commentsListContentType'); |
|
} |
|
|
|
$(document).ready(function () { |
|
getComments('#commentsListContentType'); |
|
}); |
|
|
|
|
|
//// Blind |
|
|
|
webgoat.customjs.blindXXE = function() { |
|
var commentInput = $("#commentInputBlind").val(); |
|
var xml = '<?xml version="1.0"?>' + |
|
'<comment>' + |
|
' <text>' + commentInput + '</text>' + |
|
'</comment>'; |
|
return xml; |
|
} |
|
|
|
webgoat.customjs.blindXXECallback = function() { |
|
$("#commentInputBlind").val(''); |
|
getComments('#commentsListBlind'); |
|
} |
|
|
|
$(document).ready(function () { |
|
getComments('#commentsListBlind'); |
|
}); |
|
|
|
|
|
|
|
var html = '<li class="comment">' + |
|
'<div class="pull-left">' + |
|
'<img class="avatar" src="images/avatar1.png" alt="avatar"/>' + |
|
'</div>' + |
|
'<div class="comment-body">' + |
|
'<div class="comment-heading">' + |
|
'<h4 class="user">USER</h4>' + |
|
'<h5 class="time">DATETIME</h5>' + |
|
'</div>' + |
|
'<p>COMMENT</p>' + |
|
'</div>' + |
|
'</li>'; |
|
|
|
function getComments(field) { |
|
$.get("xxe/comments", function (result, status) { |
|
$(field).empty(); |
|
for (var i = 0; i < result.length; i++) { |
|
- var comment = html.replace('USER', result[i].user); |
|
- comment = comment.replace('DATETIME', result[i].dateTime); |
|
- comment = comment.replace('COMMENT', result[i].text); |
|
+ var comment = html.replace('USER', escapeHtml(result[i].user)); |
|
+ comment = comment.replace('DATETIME', escapeHtml(result[i].dateTime)); |
|
+ comment = comment.replace('COMMENT', escapeHtml(result[i].text)); |
|
$(field).append(comment); |
|
} |
|
|
|
}); |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | DOM Based Cross-Site Scripting |
CWE-79
|
clientSideFiltering.js:38
| 1 | 2025-10-17 06:27pm |
Vulnerable Code
|
html = html + '</tr>'; |
|
} |
|
html = html + '</tr></table>'; |
|
|
|
var newdiv = document.createElement("div"); |
|
newdiv.innerHTML = html; |
1 Data Flow/s detected
|
$.get("clientSideFiltering/salaries?userId=" + userId, function (result, status) { |
|
html = html + '<td>' + result[i].Salary + '</td>'; |
|
html = html + '</tr></table>'; |
Remediation Suggestion
|
+function escapeHtml(unsafe) { return unsafe.replace(/[&<"']/g, function(m) { return {'&': '&', '<': '<', '"': '"', "'": '''}[m]; }); } |
|
var dataFetched = false; |
|
|
|
function selectUser() { |
|
|
|
var newEmployeeID = $("#UserSelect").val(); |
|
document.getElementById("employeeRecord").innerHTML = document.getElementById(newEmployeeID).innerHTML; |
|
} |
|
|
|
function fetchUserData() { |
|
if (!dataFetched) { |
|
dataFetched = true; |
|
ajaxFunction(document.getElementById("userID").value); |
|
} |
|
} |
|
|
|
function ajaxFunction(userId) { |
|
$.get("clientSideFiltering/salaries?userId=" + userId, function (result, status) { |
|
var html = "<table border = '1' width = '90%' align = 'center'"; |
|
html = html + '<tr>'; |
|
html = html + '<td>UserID</td>'; |
|
html = html + '<td>First Name</td>'; |
|
html = html + '<td>Last Name</td>'; |
|
html = html + '<td>SSN</td>'; |
|
html = html + '<td>Salary</td>'; |
|
|
|
for (var i = 0; i < result.length; i++) { |
|
html = html + '<tr id = "' + result[i].UserID + '"</tr>'; |
|
- html = html + '<td>' + result[i].UserID + '</td>'; |
|
- html = html + '<td>' + result[i].FirstName + '</td>'; |
|
- html = html + '<td>' + result[i].LastName + '</td>'; |
|
- html = html + '<td>' + result[i].SSN + '</td>'; |
|
- html = html + '<td>' + result[i].Salary + '</td>'; |
|
+ html = html + '<td>' + escapeHtml(result[i].UserID) + '</td>'; |
|
+ html = html + '<td>' + escapeHtml(result[i].FirstName) + '</td>'; |
|
+ html = html + '<td>' + escapeHtml(result[i].LastName) + '</td>'; |
|
+ html = html + '<td>' + escapeHtml(result[i].SSN) + '</td>'; |
|
+ html = html + '<td>' + escapeHtml(result[i].Salary) + '</td>'; |
|
html = html + '</tr>'; |
|
} |
|
html = html + '</tr></table>'; |
|
|
|
var newdiv = document.createElement("div"); |
|
newdiv.innerHTML = html; |
|
var container = document.getElementById("hiddenEmployeeRecords"); |
|
container.appendChild(newdiv); |
|
}); |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | Path/Directory Traversal |
CWE-22
|
ProfileUploadRetrieval.java:99
| 1 | 2025-06-30 02:46pm |
Vulnerable Code
|
if (catPicture.getName().toLowerCase().contains("path-traversal-secret.jpg")) { |
|
return ResponseEntity.ok() |
|
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) |
|
.body(FileCopyUtils.copyToByteArray(catPicture)); |
|
} |
|
if (catPicture.exists()) { |
1 Data Flow/s detected
|
var id = request.getParameter("id"); |
|
new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + ".jpg"); |
|
if (catPicture.exists()) { |
Remediation Suggestion
|
package org.owasp.webgoat.lessons.pathtraversal; |
|
|
|
import java.io.File; |
|
import java.io.FileOutputStream; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
import java.net.URI; |
|
import java.net.URISyntaxException; |
|
import java.nio.file.Files; |
|
import java.util.Base64; |
|
import javax.annotation.PostConstruct; |
|
import javax.servlet.http.HttpServletRequest; |
|
import lombok.extern.slf4j.Slf4j; |
|
import org.apache.commons.lang3.RandomUtils; |
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint; |
|
import org.owasp.webgoat.container.assignments.AssignmentHints; |
|
import org.owasp.webgoat.container.assignments.AttackResult; |
|
import org.springframework.beans.factory.annotation.Value; |
|
import org.springframework.core.io.ClassPathResource; |
|
import org.springframework.http.HttpStatus; |
|
import org.springframework.http.MediaType; |
|
import org.springframework.http.ResponseEntity; |
|
import org.springframework.security.core.token.Sha512DigestUtils; |
|
import org.springframework.util.FileCopyUtils; |
|
import org.springframework.util.StringUtils; |
|
import org.springframework.web.bind.annotation.GetMapping; |
|
import org.springframework.web.bind.annotation.PostMapping; |
|
import org.springframework.web.bind.annotation.RequestParam; |
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
import org.springframework.web.bind.annotation.RestController; |
|
|
|
@RestController |
|
@AssignmentHints({ |
|
"path-traversal-profile-retrieve.hint1", |
|
"path-traversal-profile-retrieve.hint2", |
|
"path-traversal-profile-retrieve.hint3", |
|
"path-traversal-profile-retrieve.hint4", |
|
"path-traversal-profile-retrieve.hint5", |
|
"path-traversal-profile-retrieve.hint6" |
|
}) |
|
@Slf4j |
|
public class ProfileUploadRetrieval extends AssignmentEndpoint { |
|
|
|
private final File catPicturesDirectory; |
|
|
|
public ProfileUploadRetrieval(@Value("${webgoat.server.directory}") String webGoatHomeDirectory) { |
|
this.catPicturesDirectory = new File(webGoatHomeDirectory, "/PathTraversal/" + "/cats"); |
|
this.catPicturesDirectory.mkdirs(); |
|
} |
|
|
|
@PostConstruct |
|
public void initAssignment() { |
|
for (int i = 1; i <= 10; i++) { |
|
try (InputStream is = |
|
new ClassPathResource("lessons/pathtraversal/images/cats/" + i + ".jpg") |
|
.getInputStream()) { |
|
FileCopyUtils.copy(is, new FileOutputStream(new File(catPicturesDirectory, i + ".jpg"))); |
|
} catch (Exception e) { |
|
log.error("Unable to copy pictures" + e.getMessage()); |
|
} |
|
} |
|
var secretDirectory = this.catPicturesDirectory.getParentFile().getParentFile(); |
|
try { |
|
Files.writeString( |
|
secretDirectory.toPath().resolve("path-traversal-secret.jpg"), |
|
"You found it submit the SHA-512 hash of your username as answer"); |
|
} catch (IOException e) { |
|
log.error("Unable to write secret in: {}", secretDirectory, e); |
|
} |
|
} |
|
|
|
@PostMapping("/PathTraversal/random") |
|
@ResponseBody |
|
public AttackResult execute(@RequestParam(value = "secret", required = false) String secret) { |
|
if (Sha512DigestUtils.shaHex(getWebSession().getUserName()).equalsIgnoreCase(secret)) { |
|
return success(this).build(); |
|
} |
|
return failed(this).build(); |
|
} |
|
|
|
@GetMapping("/PathTraversal/random-picture") |
|
@ResponseBody |
|
public ResponseEntity<?> getProfilePicture(HttpServletRequest request) { |
|
var queryParams = request.getQueryString(); |
|
if (queryParams != null && (queryParams.contains("..") || queryParams.contains("/"))) { |
|
return ResponseEntity.badRequest() |
|
.body("Illegal characters are not allowed in the query params"); |
|
} |
|
try { |
|
var id = request.getParameter("id"); |
|
var catPicture = |
|
new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + ".jpg"); |
|
+ String normalizedPath = catPicture.getCanonicalPath(); |
|
+ if (!normalizedPath.startsWith(new File(catPicturesDirectory).getCanonicalPath())) { |
|
+ return ResponseEntity.badRequest().body("Error: Attempt to access file outside of the base directory."); |
|
+ } |
|
|
|
+ |
|
if (catPicture.getName().toLowerCase().contains("path-traversal-secret.jpg")) { |
|
return ResponseEntity.ok() |
|
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) |
|
.body(FileCopyUtils.copyToByteArray(catPicture)); |
|
} |
|
if (catPicture.exists()) { |
|
return ResponseEntity.ok() |
|
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) |
|
.location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName())) |
|
.body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(catPicture))); |
|
} |
|
return ResponseEntity.status(HttpStatus.NOT_FOUND) |
|
.location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName())) |
|
.body( |
|
StringUtils.arrayToCommaDelimitedString(catPicture.getParentFile().listFiles()) |
|
.getBytes()); |
|
} catch (IOException | URISyntaxException e) { |
|
log.error("Image not found", e); |
|
} |
|
|
|
return ResponseEntity.badRequest().build(); |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior Path/Directory Traversal Training
Videos
Secure Code Warrior Path/Directory Traversal Video
Further Reading
OWASP Path Traversal
OWASP Input Validation Cheat Sheet
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
| |
High | SQL Injection |
CWE-89
|
Assignment5.java:60
| 1 | 2025-06-30 02:46pm |
Vulnerable Code
|
if (!"Larry".equals(username_login)) { |
|
return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build(); |
|
} |
|
try (var connection = dataSource.getConnection()) { |
|
PreparedStatement statement = |
|
connection.prepareStatement( |
1 Data Flow/s detected
|
public AttackResult login( |
|
"select password from challenge_users where userid = '" |
|
connection.prepareStatement( |
Remediation Suggestion
|
/* |
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ |
|
* |
|
* Copyright (c) 2002 - 2019 Bruce Mayhew |
|
* |
|
* This program is free software; you can redistribute it and/or modify it under the terms of the |
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the |
|
* License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without |
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
* General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License along with this program; if |
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
|
* 02111-1307, USA. |
|
* |
|
* Getting Source ============== |
|
* |
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. |
|
*/ |
|
|
|
package org.owasp.webgoat.lessons.challenges.challenge5; |
|
|
|
import java.sql.PreparedStatement; |
|
import java.sql.ResultSet; |
|
import lombok.extern.slf4j.Slf4j; |
|
import org.owasp.webgoat.container.LessonDataSource; |
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint; |
|
import org.owasp.webgoat.container.assignments.AttackResult; |
|
import org.owasp.webgoat.lessons.challenges.Flag; |
|
import org.springframework.util.StringUtils; |
|
import org.springframework.web.bind.annotation.PostMapping; |
|
import org.springframework.web.bind.annotation.RequestParam; |
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
import org.springframework.web.bind.annotation.RestController; |
|
|
|
@RestController |
|
@Slf4j |
|
public class Assignment5 extends AssignmentEndpoint { |
|
|
|
private final LessonDataSource dataSource; |
|
|
|
public Assignment5(LessonDataSource dataSource) { |
|
this.dataSource = dataSource; |
|
} |
|
|
|
@PostMapping("/challenge/5") |
|
@ResponseBody |
|
public AttackResult login( |
|
@RequestParam String username_login, @RequestParam String password_login) throws Exception { |
|
if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) { |
|
return failed(this).feedback("required4").build(); |
|
} |
|
if (!"Larry".equals(username_login)) { |
|
return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build(); |
|
} |
|
try (var connection = dataSource.getConnection()) { |
|
PreparedStatement statement = |
|
connection.prepareStatement( |
|
- "select password from challenge_users where userid = '" |
|
- + username_login |
|
- + "' and password = '" |
|
- + password_login |
|
- + "'"); |
|
+ "select password from challenge_users where userid = ? and password = ?"); |
|
+ statement.setString(1, username_login); |
|
+ statement.setString(2, password_login); |
|
ResultSet resultSet = statement.executeQuery(); |
|
|
|
if (resultSet.next()) { |
|
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build(); |
|
} else { |
|
return failed(this).feedback("challenge.close").build(); |
|
} |
|
} |
|
} |
|
} |
Remediation feedback:
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
Secure Code Warrior Training Material
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
Suppress Finding
Note: GitHub may take a few seconds to process actions triggered via checkboxes.
Please wait until the change is visible before continuing.
|
Code Security Report
Scan Metadata
Latest Scan: 2026-06-23 04:59pm
Total Findings: 116 | New Findings: 5 | Resolved Findings: 3
Tested Project Files: 494
Detected Programming Languages: 3 (JavaScript / TypeScript*, Python*, Java*)
Most Relevant Findings
Automatic Remediation Available (10)
CWE-79
stored-xss.js:40
WebGoat3/src/main/resources/lessons/xss/js/stored-xss.js
Lines 35 to 40 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/resources/lessons/xss/js/stored-xss.js
Line 35 in 38b246b
WebGoat3/src/main/resources/lessons/xss/js/stored-xss.js
Line 39 in 38b246b
WebGoat3/src/main/resources/lessons/xss/js/stored-xss.js
Line 40 in 38b246b
WebGoat3/diffs/21e29047-0f07-4b72-a2cf-6cec866619c1/stored-xss.js.diff
Lines 1 to 49 in 55772cf
✔️ Pull request created
Remediation feedback:
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
CWE-89
SqlInjectionLesson8.java:158
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Lines 153 to 158 in 38b246b
2 Data Flow/s detected
View Data Flow 1
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 59 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 60 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 63 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 66 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 77 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 147 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 148 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 154 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 158 in 38b246b
View Data Flow 2
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java
Line 60 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java
Line 61 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java
Line 64 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java
Line 67 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java
Line 75 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 147 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 148 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 154 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java
Line 158 in 38b246b
WebGoat3/diffs/aa3658e7-0888-4160-97e3-afe7a0c270c8/SqlInjectionLesson8.java.diff
Lines 1 to 174 in e115d2a
Remediation feedback:
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
CWE-89
SqlInjectionLesson6a.java:74
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Lines 69 to 74 in 38b246b
3 Data Flow/s detected
View Data Flow 1
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 56 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 57 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 62 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 66 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 74 in 38b246b
View Data Flow 2
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidation.java
Line 47 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidation.java
Line 51 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 62 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 66 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 74 in 38b246b
View Data Flow 3
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java
Line 51 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java
Line 53 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java
Line 57 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 62 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 66 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java
Line 74 in 38b246b
WebGoat3/diffs/8e4edd57-33a1-468f-989f-3baae0893443/SqlInjectionLesson6a.java.diff
Lines 1 to 121 in 89b44d5
Remediation feedback:
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
CWE-22
ProfileZipSlip.java:75
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java
Lines 70 to 75 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java
Line 73 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java
Line 75 in 38b246b
WebGoat3/diffs/bfcf534e-e303-494b-9fbe-5697cf027da0/ProfileZipSlip.java.diff
Lines 1 to 109 in 9adc35e
Remediation feedback:
Training
Secure Code Warrior Path/Directory Traversal Training
Videos
Secure Code Warrior Path/Directory Traversal Video
Further Reading
OWASP Path Traversal
OWASP Input Validation Cheat Sheet
CWE-89
JWTFinalEndpoint.java:89
WebGoat3/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java
Lines 84 to 89 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java
Line 84 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java
Line 90 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java
Line 89 in 38b246b
WebGoat3/diffs/119a3857-8cb9-4bc6-b8bb-70ea69c233ae/JWTFinalEndpoint.java.diff
Lines 1 to 124 in 4a416cb
Remediation feedback:
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
CWE-79
jwt-voting.js:63
WebGoat3/src/main/resources/lessons/jwt/js/jwt-voting.js
Lines 58 to 63 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/resources/lessons/jwt/js/jwt-voting.js
Line 43 in 38b246b
WebGoat3/src/main/resources/lessons/jwt/js/jwt-voting.js
Line 56 in 38b246b
WebGoat3/src/main/resources/lessons/jwt/js/jwt-voting.js
Line 59 in 38b246b
WebGoat3/src/main/resources/lessons/jwt/js/jwt-voting.js
Line 61 in 38b246b
WebGoat3/src/main/resources/lessons/jwt/js/jwt-voting.js
Line 63 in 38b246b
WebGoat3/diffs/8797c644-c4ac-45ea-acfe-ead0eac3eac7/jwt-voting.js.diff
Lines 1 to 88 in fb1bc93
Remediation feedback:
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
CWE-79
xxe.js:78
WebGoat3/src/main/resources/lessons/xxe/js/xxe.js
Lines 73 to 78 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/resources/lessons/xxe/js/xxe.js
Line 72 in 38b246b
WebGoat3/src/main/resources/lessons/xxe/js/xxe.js
Line 77 in 38b246b
WebGoat3/src/main/resources/lessons/xxe/js/xxe.js
Line 78 in 38b246b
WebGoat3/diffs/a715957c-cc93-4462-b769-905e1af67de9/xxe.js.diff
Lines 1 to 95 in 9f80384
Remediation feedback:
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
CWE-79
clientSideFiltering.js:38
WebGoat3/src/main/resources/lessons/clientsidefiltering/js/clientSideFiltering.js
Lines 33 to 38 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/resources/lessons/clientsidefiltering/js/clientSideFiltering.js
Line 17 in 38b246b
WebGoat3/src/main/resources/lessons/clientsidefiltering/js/clientSideFiltering.js
Line 32 in 38b246b
WebGoat3/src/main/resources/lessons/clientsidefiltering/js/clientSideFiltering.js
Line 33 in 38b246b
WebGoat3/src/main/resources/lessons/clientsidefiltering/js/clientSideFiltering.js
Line 35 in 38b246b
WebGoat3/src/main/resources/lessons/clientsidefiltering/js/clientSideFiltering.js
Line 38 in 38b246b
WebGoat3/diffs/f7883a34-8bb0-48e4-8ab4-5793a61307f8/clientSideFiltering.js.diff
Lines 1 to 48 in f827230
Remediation feedback:
Training
Secure Code Warrior DOM Based Cross-Site Scripting Training
Videos
Secure Code Warrior DOM Based Cross-Site Scripting Video
CWE-22
ProfileUploadRetrieval.java:99
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java
Lines 94 to 99 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java
Line 90 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java
Line 92 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java
Line 99 in 38b246b
WebGoat3/diffs/a7156bb3-220f-40a3-99ff-35ff669a335f/ProfileUploadRetrieval.java.diff
Lines 1 to 121 in 41b7081
Remediation feedback:
Training
Secure Code Warrior Path/Directory Traversal Training
Videos
Secure Code Warrior Path/Directory Traversal Video
Further Reading
OWASP Path Traversal
OWASP Input Validation Cheat Sheet
CWE-89
Assignment5.java:60
WebGoat3/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java
Lines 55 to 60 in 38b246b
1 Data Flow/s detected
WebGoat3/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java
Line 50 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java
Line 61 in 38b246b
WebGoat3/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java
Line 60 in 38b246b
WebGoat3/diffs/50ec1b74-71e0-46f7-b134-52df501ff9e8/Assignment5.java.diff
Lines 1 to 78 in 4acbfbb
Remediation feedback:
Training
Secure Code Warrior SQL Injection Training
Videos
Secure Code Warrior SQL Injection Video
Further Reading
OWASP SQL Injection Prevention Cheat Sheet
OWASP SQL Injection
OWASP Query Parameterization Cheat Sheet
Findings Overview