Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: "CodeQL Analysis"

on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]
schedule:
- cron: '15 2 * * 1' # Weekly on Mondays at 2:15 AM

jobs:
analyze:
name: Analyze Java Code
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'java' ]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
build-mode: none
dependency-caching: true

# Autobuild attempts to build any compiled languages (Java, C#, Go, etc.)
# If this step fails, remove it and run the build manually instead
#- name: Autobuild
# uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
46 changes: 46 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar

# Compiled class files
*.class

# Log files
*.log

# IDE files
.idea/
*.iws
*.iml
*.ipr
.vscode/
.settings/
.project
.classpath

# OS generated files
.DS_Store
Thumbs.db

# Temporary files
*.tmp
*.bak
*.swp
*~.nib

# Package files
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,56 @@
# coding-agent-example-java-codeql-autobuild
# coding-agent-example-java-codeql-autobuild

A demonstration Java application with intentional security vulnerabilities for CodeQL scanning.

## Overview

This repository contains a simple Java application built with Maven that includes several common security vulnerabilities designed to be detected by GitHub's CodeQL static analysis tool.

## Application Structure

- **Main Application**: `com.example.app.VulnerableApplication` - Entry point that demonstrates various vulnerabilities
- **Database Layer**: `com.example.database.UserDatabase` - Contains SQL injection vulnerabilities
- **Security Utils**: `com.example.security.CryptoUtils` - Contains weak cryptographic implementations
- **Web/File Handling**: `com.example.web.FileController` - Contains path traversal and command injection vulnerabilities
- **LDAP Authentication**: `com.example.ldap.LdapAuth` - Contains LDAP injection vulnerabilities

## Intentional Vulnerabilities

This application contains the following types of security vulnerabilities:

1. **SQL Injection** - Direct string concatenation in SQL queries
2. **Command Injection** - Unsanitized user input passed to system commands
3. **Path Traversal** - File operations without path validation
4. **LDAP Injection** - Unescaped user input in LDAP filters
5. **Weak Cryptography** - Use of MD5 and weak random number generation
6. **Hard-coded Secrets** - Embedded credentials and encryption keys

## CodeQL Analysis

The repository includes a GitHub Actions workflow (`.github/workflows/codeql-analysis.yml`) that:

- Runs CodeQL analysis on push and pull requests
- Uses the autobuild functionality for Java
- Includes security-and-quality queries for comprehensive coverage
- Runs weekly scheduled scans

## Building and Running

```bash
# Compile the application
mvn clean compile

# Run tests
mvn test

# Run the application (demonstrates vulnerabilities)
mvn exec:java -Dexec.mainClass="com.example.app.VulnerableApplication"
```

## Warning

⚠️ **This application contains intentional security vulnerabilities and should never be deployed in a production environment.** It is designed solely for educational purposes and CodeQL demonstration.

## License

This project is for educational and demonstration purposes only.
94 changes: 94 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>vulnerable-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<name>Vulnerable Java Application - Test2</name>
<description>A simple Java application with intentional vulnerabilities for CodeQL scanning demonstration</description>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<!-- NOTE: Some dependency versions below may have known vulnerabilities.
This is intentional for demonstration purposes. In a real application,
always use the latest secure versions of dependencies. -->

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.1-jre</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

<!-- Database connectivity for SQL injection demos -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>

<!-- Web framework for HTTP vulnerabilities -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.21</version>
</dependency>

<!-- JSON processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>

<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
</plugin>
</plugins>
</build>
</project>
50 changes: 50 additions & 0 deletions src/main/java/com/example/app/VulnerableApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.example.app;

import com.example.database.UserDatabase;
import com.example.security.CryptoUtils;
import com.example.web.FileController;
import com.example.ldap.LdapAuth;

/**
* Main application class demonstrating various Java vulnerabilities
* that should be detected by CodeQL scanning.
*/
public class VulnerableApplication {

public static void main(String[] args) {
System.out.println("Starting Vulnerable Application...");

// Demonstrate various vulnerable components
UserDatabase userDb = new UserDatabase();
CryptoUtils crypto = new CryptoUtils();
FileController fileController = new FileController();
LdapAuth ldapAuth = new LdapAuth();

// Example usage that would trigger vulnerabilities
String userInput = args.length > 0 ? args[0] : "admin";
String password = args.length > 1 ? args[1] : "password123";

// SQL Injection vulnerability
userDb.authenticateUser(userInput, password);
userDb.deleteUser(userInput);

// Weak cryptography
String token = crypto.generateToken();
System.out.println("Generated token: " + token);

// Path traversal vulnerability
String filename = args.length > 2 ? args[2] : "../../etc/passwd";
fileController.readFile(filename);

// Command injection
String command = args.length > 3 ? args[3] : "ls -la";
fileController.executeCommand(command);
fileController.executeSystemCommand(command);

// LDAP injection
ldapAuth.authenticateUser(userInput, password);
ldapAuth.getUserInfo(userInput);

System.out.println("Application completed.");
}
}
90 changes: 90 additions & 0 deletions src/main/java/com/example/database/UserDatabase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.example.database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
* Database class with intentional SQL injection vulnerabilities
* to demonstrate CodeQL detection capabilities.
*/
public class UserDatabase {

private static final String DB_URL = "jdbc:mysql://localhost:3306/testdb";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "password";

/**
* VULNERABLE: SQL Injection vulnerability - user input directly concatenated
* This should trigger a high/critical CodeQL alert
*/
public boolean authenticateUser(String username, String password) {
try {
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
Statement stmt = conn.createStatement();

// VULNERABILITY: Direct string concatenation leads to SQL injection
String query = "SELECT * FROM users WHERE username = '" + username +
"' AND password = '" + password + "'";

System.out.println("Executing query: " + query);
ResultSet rs = stmt.executeQuery(query);

Check failure

Code scanning / CodeQL

Query built by concatenation with a possibly-untrusted string High

Query built by concatenation with
this expression
, which may be untrusted.
Query built by concatenation with
this expression
, which may be untrusted.

Copilot Autofix

AI 4 months ago

To fix the problem, all SQL queries using user input must be refactored to use parameterized/prepared statements rather than direct string concatenation. Specifically for the error on line 32 (and similar patterns elsewhere), the query should be changed to include ? placeholders for inputs, and then the input values set using the appropriate setString methods before execution. This means changing the authenticateUser method to use a PreparedStatement, constructing the query as "SELECT * FROM users WHERE username = ? AND password = ?", then setting the values for both placeholders using setString(1, username) and setString(2, password) respectively. Similar changes should be made to the other methods (updateUserProfile, deleteUser) to replace concatenated statements with parameterized queries, using PreparedStatement and passing the variables safely to the SQL engine.

Changes should occur only in code snippets shown (within src/main/java/com/example/database/UserDatabase.java), and only in the affected methods. Additional required imports (for PreparedStatement) should also be added. Functionality is preserved: the logic now runs with safe, parameterized queries.

Suggested changeset 1
src/main/java/com/example/database/UserDatabase.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/com/example/database/UserDatabase.java b/src/main/java/com/example/database/UserDatabase.java
--- a/src/main/java/com/example/database/UserDatabase.java
+++ b/src/main/java/com/example/database/UserDatabase.java
@@ -4,6 +4,7 @@
 import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.Statement;
+import java.sql.PreparedStatement;
 
 /**
  * Database class with intentional SQL injection vulnerabilities
@@ -22,19 +23,18 @@
     public boolean authenticateUser(String username, String password) {
         try {
             Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
-            Statement stmt = conn.createStatement();
+            String query = "SELECT * FROM users WHERE username = ? AND password = ?";
+            PreparedStatement pstmt = conn.prepareStatement(query);
+            pstmt.setString(1, username);
+            pstmt.setString(2, password);
             
-            // VULNERABILITY: Direct string concatenation leads to SQL injection
-            String query = "SELECT * FROM users WHERE username = '" + username + 
-                          "' AND password = '" + password + "'";
+            System.out.println("Executing query (safe, parameterized): " + query);
+            ResultSet rs = pstmt.executeQuery();
             
-            System.out.println("Executing query: " + query);
-            ResultSet rs = stmt.executeQuery(query);
-            
             boolean authenticated = rs.next();
             
             rs.close();
-            stmt.close();
+            pstmt.close();
             conn.close();
             
             return authenticated;
@@ -51,16 +46,15 @@
     public void updateUserProfile(String userId, String email, String fullName) {
         try {
             Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
-            Statement stmt = conn.createStatement();
+            String updateQuery = "UPDATE users SET email = ?, full_name = ? WHERE user_id = ?";
+            PreparedStatement pstmt = conn.prepareStatement(updateQuery);
+            pstmt.setString(1, email);
+            pstmt.setString(2, fullName);
+            pstmt.setString(3, userId);
             
-            // VULNERABILITY: String concatenation in UPDATE statement
-            String updateQuery = "UPDATE users SET email = '" + email + 
-                               "', full_name = '" + fullName + 
-                               "' WHERE user_id = " + userId;
+            pstmt.executeUpdate();
             
-            stmt.executeUpdate(updateQuery);
-            
-            stmt.close();
+            pstmt.close();
             conn.close();
             
         } catch (Exception e) {
@@ -74,13 +66,12 @@
     public void deleteUser(String userIdParam) {
         try {
             Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
-            Statement stmt = conn.createStatement();
+            String sql = "DELETE FROM users WHERE id = ?";
+            PreparedStatement pstmt = conn.prepareStatement(sql);
+            pstmt.setString(1, userIdParam);
+            pstmt.executeUpdate();
             
-            // VULNERABILITY: Direct concatenation in DELETE statement
-            String sql = "DELETE FROM users WHERE id = " + userIdParam;
-            stmt.executeUpdate(sql);
-            
-            stmt.close();
+            pstmt.close();
             conn.close();
             
         } catch (Exception e) {
EOF
Copilot is powered by AI and may make mistakes. Always verify output.

boolean authenticated = rs.next();

rs.close();
stmt.close();
conn.close();

return authenticated;

} catch (Exception e) {
System.err.println("Database error: " + e.getMessage());
return false;
}
}

/**
* VULNERABLE: Another SQL injection point
*/
public void updateUserProfile(String userId, String email, String fullName) {
try {
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
Statement stmt = conn.createStatement();

// VULNERABILITY: String concatenation in UPDATE statement
String updateQuery = "UPDATE users SET email = '" + email +
"', full_name = '" + fullName +
"' WHERE user_id = " + userId;

stmt.executeUpdate(updateQuery);

Check failure

Code scanning / CodeQL

Query built by concatenation with a possibly-untrusted string High

Query built by concatenation with
this expression
, which may be untrusted.
Query built by concatenation with
this expression
, which may be untrusted.

Copilot Autofix

AI 4 months ago

General fix:
Avoid direct concatenation of potentially untrusted input into SQL queries. Instead, use prepared statements, with parameter placeholders (?) for each value derived from user input, and provide those values with the appropriate setter methods (e.g., setString, setInt).

Detailed description:
Replace the creation of the Statement with a PreparedStatement. Change the construction of updateQuery from using concatenation, to using a parameterized SQL statement with question mark placeholders for email, fullName, and userId. Replace the call to stmt.executeUpdate(updateQuery) with the use of the PreparedStatement, after setting its parameters in the correct order with .setString() or the appropriate setter. Remember to close the PreparedStatement instead of the old Statement.

What needs to be changed:

  • Replace creation of Statement stmt = conn.createStatement() with a PreparedStatement with parameters.
  • Rewrite the SQL to use ? placeholders.
  • Set each parameter using the relevant setter.
  • Replace uses of stmt with preparedStatement as appropriate.
  • Close the PreparedStatement.
  • Add import for java.sql.PreparedStatement at the top if not present.
Suggested changeset 1
src/main/java/com/example/database/UserDatabase.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/com/example/database/UserDatabase.java b/src/main/java/com/example/database/UserDatabase.java
--- a/src/main/java/com/example/database/UserDatabase.java
+++ b/src/main/java/com/example/database/UserDatabase.java
@@ -4,6 +4,7 @@
 import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.Statement;
+import java.sql.PreparedStatement;
 
 /**
  * Database class with intentional SQL injection vulnerabilities
@@ -51,16 +52,15 @@
     public void updateUserProfile(String userId, String email, String fullName) {
         try {
             Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
-            Statement stmt = conn.createStatement();
+            String updateQuery = "UPDATE users SET email = ?, full_name = ? WHERE user_id = ?";
+            PreparedStatement pstmt = conn.prepareStatement(updateQuery);
+            pstmt.setString(1, email);
+            pstmt.setString(2, fullName);
+            pstmt.setString(3, userId);
             
-            // VULNERABILITY: String concatenation in UPDATE statement
-            String updateQuery = "UPDATE users SET email = '" + email + 
-                               "', full_name = '" + fullName + 
-                               "' WHERE user_id = " + userId;
+            pstmt.executeUpdate();
             
-            stmt.executeUpdate(updateQuery);
-            
-            stmt.close();
+            pstmt.close();
             conn.close();
             
         } catch (Exception e) {
EOF
@@ -4,6 +4,7 @@
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;

/**
* Database class with intentional SQL injection vulnerabilities
@@ -51,16 +52,15 @@
public void updateUserProfile(String userId, String email, String fullName) {
try {
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
Statement stmt = conn.createStatement();
String updateQuery = "UPDATE users SET email = ?, full_name = ? WHERE user_id = ?";
PreparedStatement pstmt = conn.prepareStatement(updateQuery);
pstmt.setString(1, email);
pstmt.setString(2, fullName);
pstmt.setString(3, userId);

// VULNERABILITY: String concatenation in UPDATE statement
String updateQuery = "UPDATE users SET email = '" + email +
"', full_name = '" + fullName +
"' WHERE user_id = " + userId;
pstmt.executeUpdate();

stmt.executeUpdate(updateQuery);

stmt.close();
pstmt.close();
conn.close();

} catch (Exception e) {
Copilot is powered by AI and may make mistakes. Always verify output.

stmt.close();
conn.close();

} catch (Exception e) {
System.err.println("Update failed: " + e.getMessage());
}
}

/**
* VULNERABLE: Dynamic query construction - another SQL injection pattern
*/
public void deleteUser(String userIdParam) {
try {
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
Statement stmt = conn.createStatement();

// VULNERABILITY: Direct concatenation in DELETE statement
String sql = "DELETE FROM users WHERE id = " + userIdParam;
stmt.executeUpdate(sql);

stmt.close();
conn.close();

} catch (Exception e) {
System.err.println("Delete failed: " + e.getMessage());
}
}
}
Loading