Skip to content

Vulnerability fix (powered by Mobb Autofixer)#142

Open
antonychiu2 wants to merge 6 commits intomainfrom
Mobb-fix-a8cc994ec8
Open

Vulnerability fix (powered by Mobb Autofixer)#142
antonychiu2 wants to merge 6 commits intomainfrom
Mobb-fix-a8cc994ec8

Conversation

@antonychiu2
Copy link
Owner

This change fixes 6 issues reported by Codeql.

SQL Injection (6)

Issue description

SQL Injection allows attackers to execute malicious SQL queries by manipulating input data. This can result in unauthorized access to sensitive data, data manipulation, or even complete database compromise.

Fix instructions

Use parameterized queries or prepared statements to sanitize user input and prevent manipulation of the SQL query.

Additional info and fix customization on Mobb platform

SQL_Injection fix 1 SQL_Injection fix 2 SQL_Injection fix 3 SQL_Injection fix 4 SQL_Injection fix 5 SQL_Injection fix 6

log(connection, query);
ResultSet results = statement.executeQuery(query);
statement.setString(1, auth_tan);
ResultSet results = statement.executeQuery();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
Detected a formatted string in a SQL statement. This could lead to SQL injection if variables in the SQL statement are not properly sanitized. Use a prepared statements (java.sql.PreparedStatement) instead. You can obtain a PreparedStatement using 'connection.prepareStatement'.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L67 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 67] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L65 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 65] query</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L72 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 72] statement</a>"]
        end
            v2 --> v3
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L77 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 77] statement.executeQuery()</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
ResultSet results = statement.executeQuery();
String query =
"SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
try (Connection connection = dataSource.getConnection()) {
try {
PreparedStatement statement =
connection.prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
log(connection, query);
statement.setString(1, name);
statement.setString(2, auth_tan); // Securely parameterize auth_tan
ResultSet results = statement.executeQuery();
View step-by-step instructions
  1. Change the SQL query construction to remove direct concatenation of the name variable into the statement. Instead, use a parameter placeholder (?) for both input values.
  2. Update the query assignment to:
    String query = "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
  3. After preparing the statement, bind the name parameter to index 1 with statement.setString(1, name).
  4. Bind the auth_tan parameter to index 2 with statement.setString(2, auth_tan).
  5. Remove any previous code that concatenates user inputs into the SQL statement.

This prevents SQL injection by making sure user inputs are not assembled directly into the SQL command string. Prepared statements ensure proper escaping of parameters.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by formatted-sql-string.

You can view more details about this finding in the Semgrep AppSec Platform.

Comment on lines 68 to +70
"SELECT * FROM employees WHERE last_name = '"
+ name
+ "' AND auth_tan = '"
+ auth_tan
+ "'";
+ "' AND auth_tan = ?";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
User data flows into this manually-constructed SQL string. User data can be safely inserted into SQL strings using prepared statements or an object-relational mapper (ORM). Manually-constructed SQL strings is a possible indicator of SQL injection, which could let an attacker steal or manipulate data from the database. Instead, use prepared statements (connection.PreparedStatement) or a safe library.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L61 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 61] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L61 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 61] name</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L62 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 62] injectableQueryIntegrity</a>"]

            v4["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L65 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 65] name</a>"]
        end
            v2 --> v3
            v3 --> v4
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L68 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 68] &quot;SELECT * FROM employees WHERE last_name = &apos;&quot;<br>            + name<br>            + &quot;&apos; AND auth_tan = ?&quot;</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
"SELECT * FROM employees WHERE last_name = '"
+ name
+ "' AND auth_tan = '"
+ auth_tan
+ "'";
+ "' AND auth_tan = ?";
// Use a parameterized query to prevent SQL injection
String query = "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
View step-by-step instructions
  1. Change the SQL query construction so that user-provided data (name) is not directly concatenated into the query string.
  2. Use a parameterized query with placeholders instead of concatenation. For example, rewrite the query as: "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?"
  3. Create the prepared statement with this parameterized query: PreparedStatement statement = connection.prepareStatement(query, ...)
  4. Set the value for the first parameter (last_name) using statement.setString(1, name)
  5. Set the value for the second parameter (auth_tan) using statement.setString(2, auth_tan)
  6. Execute the query as usual.

This change will ensure that the SQL driver safely handles the user-provided data and prevents SQL injection vulnerabilities.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by tainted-sql-string.

You can view more details about this finding in the Semgrep AppSec Platform.

try (Connection connection = dataSource.getConnection()) {
try {
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
Untrusted input might be used to build a database query, which can lead to a SQL injection vulnerability. An attacker can execute malicious SQL statements and gain unauthorized access to sensitive data, modify, delete data, or execute arbitrary system commands. To prevent this vulnerability, use prepared statements that do not concatenate user-controllable strings and use parameterized queries where SQL commands and user data are strictly separated. Also, consider using an object-relational (ORM) framework to operate with safer abstractions. To build SQL queries safely in Java, it is possible to adopt prepared statements by using the java.sql.PreparedStatement class with bind variables.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L61 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 61] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L61 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 61] name</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L62 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 62] injectableQueryIntegrity</a>"]

            v4["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L65 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 65] name</a>"]

            v5["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L67 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 67] query</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L73 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 73] query</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
// Fix: Parameterize both 'name' and 'auth_tan' to prevent SQL injection.
String query = "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
SqlInjectionLesson8.log(connection, query);
statement.setString(1, name);
statement.setString(2, auth_tan);
ResultSet results = statement.executeQuery();
View step-by-step instructions
  1. Update your SQL query string so that all user-controllable values are parameterized using ? placeholders, rather than directly concatenating inputs like name into the query. For example, instead of "'SELECT * FROM employees WHERE last_name = '" + name + "' AND auth_tan = ?'", use "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?".
  2. Pass both user input values to the prepared statement using statement.setString. For example:
    • statement.setString(1, name);
    • statement.setString(2, auth_tan);
  3. Ensure the query preparation and execution looks like this:
    • PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
    • SqlInjectionLesson8.log(connection, query);
    • statement.setString(1, name);
    • statement.setString(2, auth_tan);
    • ResultSet results = statement.executeQuery();

By parameterizing all user input in your SQL queries, you prevent attackers from injecting malicious statements, since the database treats input values as data, not as a part of the query syntax.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by java-sql-sqli.

You can view more details about this finding in the Semgrep AppSec Platform.

Comment on lines 66 to +68
"SELECT * FROM employees WHERE last_name = '"
+ name
+ "' AND auth_tan = '"
+ auth_tan
+ "'";
+ "' AND auth_tan = ?";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
User data flows into this manually-constructed SQL string. User data can be safely inserted into SQL strings using prepared statements or an object-relational mapper (ORM). Manually-constructed SQL strings is a possible indicator of SQL injection, which could let an attacker steal or manipulate data from the database. Instead, use prepared statements (connection.PreparedStatement) or a safe library.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L59 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 59] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L59 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 59] name</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L60 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 60] injectableQueryConfidentiality</a>"]

            v4["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L63 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 63] name</a>"]
        end
            v2 --> v3
            v3 --> v4
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L66 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 66] &quot;SELECT * FROM employees WHERE last_name = &apos;&quot;<br>            + name<br>            + &quot;&apos; AND auth_tan = ?&quot;</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
"SELECT * FROM employees WHERE last_name = '"
+ name
+ "' AND auth_tan = '"
+ auth_tan
+ "'";
+ "' AND auth_tan = ?";
// Use parameter placeholders for both 'name' and 'auth_tan'
String query =
"SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
View step-by-step instructions
  1. Change the way you construct the query string to use parameter placeholders (?) for all user input.
    Instead of including name directly in the SQL string, use: "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?"
  2. Remove the string concatenation with name from the query definition.
  3. Set the parameters for both name and auth_tan in the PreparedStatement using statement.setString(1, name) and statement.setString(2, auth_tan).
  4. Adjust any references to parameter indexes, since there will now be two parameters to set.

Prepared statements safely handle user input by ensuring input values are never parsed as SQL.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by tainted-sql-string.

You can view more details about this finding in the Semgrep AppSec Platform.

try (Connection connection = dataSource.getConnection()) {
try {
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
Untrusted input might be used to build a database query, which can lead to a SQL injection vulnerability. An attacker can execute malicious SQL statements and gain unauthorized access to sensitive data, modify, delete data, or execute arbitrary system commands. To prevent this vulnerability, use prepared statements that do not concatenate user-controllable strings and use parameterized queries where SQL commands and user data are strictly separated. Also, consider using an object-relational (ORM) framework to operate with safer abstractions. To build SQL queries safely in Java, it is possible to adopt prepared statements by using the java.sql.PreparedStatement class with bind variables.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L61 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 61] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L61 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 61] name</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L62 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 62] injectableQueryIntegrity</a>"]

            v4["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L65 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 65] name</a>"]

            v5["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L67 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 67] query</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L73 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 73] query</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
String query =
"SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
try (Connection connection = dataSource.getConnection()) {
try {
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
SqlInjectionLesson8.log(connection, query);
statement.setString(1, name); // Set the 'name' parameter
statement.setString(2, auth_tan); // Set the 'auth_tan' parameter
ResultSet results = statement.executeQuery();
var test = results.getRow() != 0;
if (results.getStatement() != null) {
if (results.first()) {
output.append(SqlInjectionLesson8.generateTable(results));
} else {
// no results
return failed(this).feedback("sql-injection.8.no.results").build();
}
}
} catch (SQLException e) {
System.err.println(e.getMessage());
return failed(this)
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
.build();
}
return checkSalaryRanking(connection, output);
} catch (Exception e) {
System.err.println(e.getMessage());
return failed(this)
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
.build();
}
View step-by-step instructions
  1. Change the SQL query in injectableQueryIntegrity so that both name and auth_tan use parameter placeholders (?) rather than directly concatenating name into the query string. The query should look like: "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?".
  2. When creating the PreparedStatement, set both parameters using statement.setString(1, name); and statement.setString(2, auth_tan);, making sure to set them in the correct order as they appear in the query.
  3. Remove the string concatenation of untrusted data in the SQL query string.

This change ensures user input is never directly inserted into the SQL query, which helps prevent SQL injection attacks.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by formatted-sql-string-deepsemgrep.

You can view more details about this finding in the Semgrep AppSec Platform.

ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
PreparedStatement statement =
connection.prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
Untrusted input might be used to build a database query, which can lead to a SQL injection vulnerability. An attacker can execute malicious SQL statements and gain unauthorized access to sensitive data, modify, delete data, or execute arbitrary system commands. To prevent this vulnerability, use prepared statements that do not concatenate user-controllable strings and use parameterized queries where SQL commands and user data are strictly separated. Also, consider using an object-relational (ORM) framework to operate with safer abstractions. To build SQL queries safely in Java, it is possible to adopt prepared statements by using the java.sql.PreparedStatement class with bind variables.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L59 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 59] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L59 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 59] name</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L60 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 60] injectableQueryConfidentiality</a>"]

            v4["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L63 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 63] name</a>"]

            v5["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L65 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 65] query</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L74 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 74] query</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
// Change the query to use parameter placeholders for both 'name' and 'auth_tan'
String query =
"SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
try (Connection connection = dataSource.getConnection()) {
try {
PreparedStatement statement =
connection.prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
// Set both user inputs via safe parameter binding
statement.setString(1, name);
statement.setString(2, auth_tan);
log(connection, 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>")
View step-by-step instructions
  1. Update the SQL query so that both user inputs (name and auth_tan) are included as bind variables (i.e., placeholders), instead of concatenating name directly into the query string. Change the query construction line to:
    String query = "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
  2. In the code that prepares and sets query parameters for the PreparedStatement, set both inputs as parameters, not only auth_tan. After you prepare the statement, add:
    statement.setString(1, name);
    statement.setString(2, auth_tan);
    (Adjust indices if you have additional parameters.)
  3. Remove any direct concatenation of user data into an SQL statement string.

Prepared statements keep user-supplied input separate from the SQL command, helping prevent SQL injection attacks.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by java-sql-sqli.

You can view more details about this finding in the Semgrep AppSec Platform.

ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
PreparedStatement statement =
connection.prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
Untrusted input might be used to build a database query, which can lead to a SQL injection vulnerability. An attacker can execute malicious SQL statements and gain unauthorized access to sensitive data, modify, delete data, or execute arbitrary system commands. To prevent this vulnerability, use prepared statements that do not concatenate user-controllable strings and use parameterized queries where SQL commands and user data are strictly separated. Also, consider using an object-relational (ORM) framework to operate with safer abstractions. To build SQL queries safely in Java, it is possible to adopt prepared statements by using the java.sql.PreparedStatement class with bind variables.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L59 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 59] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L59 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 59] name</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L60 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 60] injectableQueryConfidentiality</a>"]

            v4["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L63 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 63] name</a>"]

            v5["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L65 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 65] query</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java#L74 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 74] query</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
String query =
"SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
try (Connection connection = dataSource.getConnection()) {
try {
PreparedStatement statement =
connection.prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
log(connection, query);
// Set parameters for last_name and auth_tan securely using parameterized query
statement.setString(1, name);
statement.setString(2, auth_tan);
ResultSet results = statement.executeQuery();
View step-by-step instructions
  1. Change the SQL query definition so that all user input values are replaced with placeholders (?) rather than being directly concatenated into the string. Specifically, update the line building the query variable to use a ? for the name parameter:
    String query = "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
  2. When using the PreparedStatement, set values for both placeholders with the provided user inputs. Update the lines after creating the PreparedStatement so that statement.setString(1, name); and statement.setString(2, auth_tan); are used in that order.
  3. Execute the query as normal.

By using prepared statements and bind variables for all user input, you prevent SQL injection because the input cannot alter the SQL query structure.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by formatted-sql-string-deepsemgrep.

You can view more details about this finding in the Semgrep AppSec Platform.

SqlInjectionLesson8.log(connection, query);
ResultSet results = statement.executeQuery(query);
statement.setString(1, auth_tan);
ResultSet results = statement.executeQuery();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified a blocking 🔴 issue in your code:
Detected a formatted string in a SQL statement. This could lead to SQL injection if variables in the SQL statement are not properly sanitized. Use a prepared statements (java.sql.PreparedStatement) instead. You can obtain a PreparedStatement using 'connection.prepareStatement'.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L69 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 69] name</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L67 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 67] query</a>"]

            v3["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L73 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 73] statement</a>"]
        end
            v2 --> v3
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/antonychiu2/webgoat/blob/86e1e273e8b381856b6f818c6e4d4c3ab59e7f59/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java#L76 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 76] statement.executeQuery()</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
ResultSet results = statement.executeQuery();
protected AttackResult injectableQueryIntegrity(String name, String auth_tan) {
StringBuilder output = new StringBuilder();
// Update the query to use parameter placeholders instead of direct concatenation
String query =
"SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?";
try (Connection connection = dataSource.getConnection()) {
try {
PreparedStatement statement = connection.prepareStatement(query, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
SqlInjectionLesson8.log(connection, query);
statement.setString(1, name);
statement.setString(2, auth_tan); // Bind the auth_tan parameter safely
ResultSet results = statement.executeQuery();
var test = results.getRow() != 0;
if (results.getStatement() != null) {
if (results.first()) {
output.append(SqlInjectionLesson8.generateTable(results));
} else {
// no results
return failed(this).feedback("sql-injection.8.no.results").build();
}
}
} catch (SQLException e) {
System.err.println(e.getMessage());
return failed(this)
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
.build();
}
return checkSalaryRanking(connection, output);
} catch (Exception e) {
System.err.println(e.getMessage());
return failed(this)
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
.build();
}
}
View step-by-step instructions
  1. Change the SQL query string to use a parameter placeholder (?) for auth_tan instead of concatenating it directly. For example, update the query to: "SELECT * FROM employees WHERE last_name = ? AND auth_tan = ?"
  2. Replace concatenation of auth_tan in the query string with the ? placeholder.
  3. Add statement.setString(2, auth_tan); after setting the first parameter (name) to bind the value of auth_tan safely to the query.
  4. Remove any direct concatenation of user input into the SQL query.

By updating the query to use parameter placeholders and binding all user input values, you ensure inputs are treated as data, not executable SQL code. This prevents SQL injection vulnerabilities.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by formatted-sql-string.

You can view more details about this finding in the Semgrep AppSec Platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant