Skip to content
Draft
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
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,14 @@ models-output.json
*.testproj
trap

# Java test artifacts
.gradle/
build/
db/
*.bqrs

# Gradle wrapper (should be committed in real projects, but not needed for tests)
gradle/
gradlew
gradlew.bat

174 changes: 174 additions & 0 deletions UNDERTOW_IMPLEMENTATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Undertow CodeQL Data Extension - Implementation Summary

## Overview

Successfully developed and tested a CodeQL data extension for the Undertow HTTP library in Java. The extension enables detection of Cross-Site Scripting (XSS) vulnerabilities in applications using the Undertow web server.

## Implementation Location

- **Model File**: `/languages/java/custom/src/undertow.model.yml`
- **Test Directory**: `/languages/java/custom/test/UndertowXSS/`

## Models Implemented

### 1. Remote Flow Source
- **Method**: `io.undertow.server.HttpServerExchange.getQueryParameters()`
- **Return Type**: `Map<String, Deque<String>>`
- **Description**: Captures query parameters from HTTP requests
- **Classification**: Remote user input (untrusted data source)

### 2. XSS Sinks (8 overloads)
All `io.undertow.io.Sender.send()` method overloads that write HTTP response content:
- `send(String)`
- `send(String, IoCallback)`
- `send(String, Charset)`
- `send(String, Charset, IoCallback)`
- `send(ByteBuffer)`
- `send(ByteBuffer, IoCallback)`
- `send(ByteBuffer[])`
- `send(ByteBuffer[], IoCallback)`

## Key Fixes Applied

### 1. Signature Format
**Problem**: Used JVM bytecode format `(Ljava/lang/String;)V`
**Solution**: Use CodeQL string signature format `(String)`

### 2. Boolean Capitalization
**Problem**: Used Java-style `false`
**Solution**: Use YAML/Python-style `False`

### 3. Sink Kind
**Problem**: Used generic `"xss"`
**Solution**: Use CodeQL-specific `"html-injection"` (required by `XssSink` class)

### 4. Source Access Path
**Problem**: Used overly specific `"ReturnValue.MapValue.Element"`
**Solution**: Use simplified `"ReturnValue"` (CodeQL automatically handles Map values and Collection elements)

## Test Results

βœ… **All tests passing**

### Debug Sources Query
```
| source | col1 |
+-------------------------+---------------------+
| getQueryParameters(...) | Remote source found |
```

### Debug Sinks Query
```
| sink | col1 |
+-----------+----------------+
| ... + ... | XSS sink found |
```

### Main XSS Detection Query
```
Detected 1 XSS vulnerability:
- Source: Line 17 - getQueryParameters()
- Sink: Line 22 - String concatenation in send()
- Path: Query parameter β†’ local variable β†’ string concatenation β†’ HTTP response
```

## Vulnerability Detected in Test Code

The test successfully identifies this XSS vulnerability:

```java
// Line 17: Source - User input from query parameter
Deque<String> res = exchange.getQueryParameters().get("namex");
if (res != null) {
name = res.getFirst();
}

// Line 22: Sink - Unsanitized data in HTTP response
exchange.getResponseSender().send("<html><body>Hello " + name + "</body></html>");
```

**Attack Vector**: An attacker can inject malicious JavaScript via the `namex` parameter:
```
http://localhost:8080/?namex=<script>alert('XSS')</script>
```

## Files Modified

1. **languages/java/custom/src/undertow.model.yml**
- Fixed source model (1 entry)
- Fixed sink models (8 entries)

2. **languages/java/custom/test/UndertowXSS/UndertowXSS.ql**
- Updated to use modern CodeQL module-based syntax
- Uses `RemoteFlowSource` and `XssSink` from data extensions

3. **languages/java/custom/test/UndertowXSS/UndertowXSS.expected**
- Updated to match actual CodeQL output format

## Files Created

1. **languages/java/custom/test/UndertowXSS/README.md**
- Comprehensive documentation of the models and tests

2. **languages/java/custom/test/UndertowXSS/DebugSources.ql**
- Debug query to verify source detection

3. **languages/java/custom/test/UndertowXSS/DebugSinks.ql**
- Debug query to verify sink detection

## Verification Commands

```bash
# Navigate to test directory
cd languages/java/custom/test/UndertowXSS

# Run main XSS detection query
codeql query run UndertowXSS.ql -d db/ --output=results.bqrs
codeql bqrs decode results.bqrs --format=text

# Run debug queries
codeql query run DebugSources.ql -d db/ --output=sources.bqrs
codeql bqrs decode sources.bqrs --format=text

codeql query run DebugSinks.ql -d db/ --output=sinks.bqrs
codeql bqrs decode sinks.bqrs --format=text
```

## Development Approach

Followed Test-Driven Development (TDD) principles:

1. **Red Phase**: Identified that existing models weren't working (no sources/sinks detected)
2. **Debug Phase**: Created debug queries to understand the problem
3. **Analysis Phase**: Examined method signatures and CodeQL internals
4. **Fix Phase**: Applied corrections to model format and parameters
5. **Green Phase**: Verified all queries return expected results
6. **Refactor Phase**: Cleaned up temporary debug files and added documentation

## CodeQL Version

- **CodeQL CLI**: 2.23.5
- **Java Library**: codeql/java-all@7.7.3

## Security Impact

This data extension enables CodeQL to automatically detect XSS vulnerabilities in Undertow-based applications, helping developers:
- Identify unsafe handling of user input
- Detect missing output encoding/sanitization
- Prevent injection attacks in HTTP responses
- Secure web applications at development time

## Next Steps (Optional Enhancements)

1. Add summary models for common sanitization methods
2. Add models for additional sources (cookies, headers, path parameters)
3. Add models for other security-sensitive sinks (redirects, SQL injection, etc.)
4. Create additional test cases covering edge cases
5. Submit models to CodeQL community repository

## References

- [Undertow Documentation](https://undertow.io/)
- [CodeQL Data Extensions](https://codeql.github.com/docs/codeql-language-guides/data-extensions/)
- [CodeQL XSS Query](https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-079/XSS.ql)
- [Model Format Specification](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/#model-format)
1 change: 1 addition & 0 deletions languages/java/custom/src/qlpack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ version: 0.0.1
library: false
dependencies:
codeql/java-all: "*"
dataExtensions: "*.model.yml"
38 changes: 38 additions & 0 deletions languages/java/custom/src/undertow.model.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sourceModel
data:
# HttpServerExchange.getQueryParameters() returns Map<String, Deque<String>>
# The map values contain user-controlled query parameter values
# CodeQL automatically handles Map values and Collection elements
- ["io.undertow.server", "HttpServerExchange", False, "getQueryParameters", "()", "", "ReturnValue", "remote", "manual"]

- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
# Sender.send(String) - sends response content, vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(String)", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(String, IoCallback) - sends response content, vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(String,IoCallback)", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(String, Charset) - sends response content, vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(String,Charset)", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(String, Charset, IoCallback) - sends response content, vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(String,Charset,IoCallback)", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(ByteBuffer) - sends response content, could be vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(ByteBuffer)", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(ByteBuffer, IoCallback) - sends response content, could be vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(ByteBuffer,IoCallback)", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(ByteBuffer[]) - sends response content, could be vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(ByteBuffer[])", "", "Argument[0]", "html-injection", "manual"]

# Sender.send(ByteBuffer[], IoCallback) - sends response content, could be vulnerable to XSS
- ["io.undertow.io", "Sender", False, "send", "(ByteBuffer[],IoCallback)", "", "Argument[0]", "html-injection", "manual"]

13 changes: 13 additions & 0 deletions languages/java/custom/test/UndertowXSS/DebugSinks.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @name Debug Undertow sinks
* @description Check if Undertow sinks are recognized
* @kind problem
* @id java/test/undertow-sinks-debug
*/

import java
import semmle.code.java.security.XSS

from XssSink sink
where sink.getLocation().getFile().getBaseName() = "UndertowExample.java"
select sink, "XSS sink found"
13 changes: 13 additions & 0 deletions languages/java/custom/test/UndertowXSS/DebugSources.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @name Debug Undertow sources
* @description Check if Undertow sources are recognized
* @kind problem
* @id java/test/undertow-sources-debug
*/

import java
import semmle.code.java.dataflow.FlowSources

from RemoteFlowSource source
where source.getLocation().getFile().getBaseName() = "UndertowExample.java"
select source, "Remote source found"
101 changes: 101 additions & 0 deletions languages/java/custom/test/UndertowXSS/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Undertow XSS Data Extension Tests

This directory contains tests for the Undertow HTTP library data extension models.

## Overview

The Undertow data extension models enable CodeQL to detect security vulnerabilities in applications using the [Undertow](https://undertow.io/) HTTP server library. The models define sources and sinks for taint tracking analysis.

## Models Defined

### Sources
- **`io.undertow.server.HttpServerExchange.getQueryParameters()`**
- Returns: `Map<String, Deque<String>>`
- Description: Query parameters from HTTP request (user-controlled data)
- Kind: `remote` (remote flow source)

### Sinks
- **`io.undertow.io.Sender.send(String)`**
- **`io.undertow.io.Sender.send(String, IoCallback)`**
- **`io.undertow.io.Sender.send(String, Charset)`**
- **`io.undertow.io.Sender.send(String, Charset, IoCallback)`**
- **`io.undertow.io.Sender.send(ByteBuffer)`**
- **`io.undertow.io.Sender.send(ByteBuffer, IoCallback)`**
- **`io.undertow.io.Sender.send(ByteBuffer[])`**
- **`io.undertow.io.Sender.send(ByteBuffer[], IoCallback)`**
- Description: Sends HTTP response content
- Kind: `html-injection` (XSS sink)

## Test Files

### UndertowExample.java
Example vulnerable code that demonstrates an XSS vulnerability:
- **Line 17**: User input from query parameter `namex` via `getQueryParameters()`
- **Line 22**: Unsanitized data sent in HTTP response via `send()`

### UndertowXSS.ql
Main test query that detects XSS vulnerabilities using the data extension models.

### UndertowXSS.expected
Expected test output showing the detected vulnerability.

### DebugSources.ql
Debug query to verify that sources are properly recognized.

### DebugSinks.ql
Debug query to verify that sinks are properly recognized.

## Running the Tests

### Using existing database:
```bash
# Run the main XSS detection query
codeql query run UndertowXSS.ql -d db/ --output=results.bqrs
codeql bqrs decode results.bqrs --format=text

# Run debug queries
codeql query run DebugSources.ql -d db/ --output=sources.bqrs
codeql bqrs decode sources.bqrs --format=text

codeql query run DebugSinks.ql -d db/ --output=sinks.bqrs
codeql bqrs decode sinks.bqrs --format=text
```

### Creating a new test database:
```bash
# Create database (this will also build the code)
codeql database create db-new --language=java --command="./gradlew clean build"

# Run queries against new database
codeql query run UndertowXSS.ql -d db-new/
```

## Expected Results

The main query should detect **1 XSS vulnerability**:
- **Source**: `getQueryParameters()` call on line 17
- **Sink**: String concatenation expression on line 22
- **Path**: Query parameter β†’ local variable β†’ string concatenation β†’ HTTP response

## Key Implementation Details

### Model Format Fixes Applied

1. **Signature Format**: Use CodeQL format `(String)` not JVM format `(Ljava/lang/String;)V`
2. **Boolean Values**: Use `False` (YAML/Python style) not `false` (Java style)
3. **Sink Kind**: Use `html-injection` (CodeQL XSS library expects this) not `xss`
4. **Source Access Path**: Use `ReturnValue` (CodeQL handles Map/Collection elements automatically) not `ReturnValue.MapValue.Element`

### Query Implementation

The test query uses:
- `RemoteFlowSource` class to match sources defined in the model
- `XssSink` class to match sinks defined in the model
- Modern CodeQL module-based taint tracking configuration
- `TaintTracking::Global<ConfigSig>` for global taint analysis

## References

- [Undertow Documentation](https://undertow.io/)
- [CodeQL Data Extensions Documentation](https://codeql.github.com/docs/codeql-language-guides/data-extensions/)
- [CodeQL Java Security Queries](https://github.com/github/codeql/tree/main/java/ql/src/Security)
27 changes: 27 additions & 0 deletions languages/java/custom/test/UndertowXSS/UndertowExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.example;

import io.undertow.Undertow;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import java.util.Deque;

public class UndertowExample {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(new HttpHandler() {
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
String name = "world";
Deque<String> res = exchange.getQueryParameters().get("namex"); // source
if (res != null) {
name = res.getFirst();
}
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html");
exchange.getResponseSender().send("<html><body>Hello " + name + "</body></html>"); // sink: XSS
}
}).build();
server.start();
}
}
2 changes: 2 additions & 0 deletions languages/java/custom/test/UndertowXSS/UndertowXSS.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#select
| UndertowExample.java:22:59:22:104 | ... + ... | UndertowExample.java:17:45:17:73 | getQueryParameters(...) : Map | UndertowExample.java:22:59:22:104 | ... + ... | XSS vulnerability: user input from $@ flows to HTTP response. | UndertowExample.java:17:45:17:73 | getQueryParameters(...) | remote source |
Loading
Loading