From 26dca558c764ed7f9f97542e689b0c80204bc668 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 6 May 2026 16:02:08 +0000 Subject: [PATCH 1/3] Initial plan From f5b17b0b48331dbf7b8ee7dc040cf85cd37dfeca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 6 May 2026 16:08:02 +0000 Subject: [PATCH 2/3] Add SSRF tests and stubs for Apache Http fluent Request models Agent-Logs-Url: https://github.com/github/codeql/sessions/bd4fa112-dbc3-47e8-9cef-9b1b13c7e549 Co-authored-by: owen-mc <62447351+owen-mc@users.noreply.github.com> --- .../CWE-918/ApacheHttpFluentSSRF.java | 40 +++++++++++++++++++ .../test/query-tests/security/CWE-918/options | 2 +- .../apache/http/client/fluent/Request.java | 26 ++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java create mode 100644 java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java diff --git a/java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java b/java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java new file mode 100644 index 000000000000..df765ea060bd --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java @@ -0,0 +1,40 @@ +import java.io.IOException; +import java.net.URI; + +import org.apache.http.client.fluent.Request; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class ApacheHttpFluentSSRF extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + try { + + String sink = request.getParameter("uri"); // $ Source + URI uri = new URI(sink); + + Request.Delete(sink); // $ Alert + Request.Delete(uri); // $ Alert + Request.Get(sink); // $ Alert + Request.Get(uri); // $ Alert + Request.Head(sink); // $ Alert + Request.Head(uri); // $ Alert + Request.Options(sink); // $ Alert + Request.Options(uri); // $ Alert + Request.Patch(sink); // $ Alert + Request.Patch(uri); // $ Alert + Request.Post(sink); // $ Alert + Request.Post(uri); // $ Alert + Request.Put(sink); // $ Alert + Request.Put(uri); // $ Alert + Request.Trace(sink); // $ Alert + Request.Trace(uri); // $ Alert + + } catch (Exception e) { + // TODO: handle exception + } + } +} diff --git a/java/ql/test/query-tests/security/CWE-918/options b/java/ql/test/query-tests/security/CWE-918/options index 6b6efaeca544..04f8cec9345c 100644 --- a/java/ql/test/query-tests/security/CWE-918/options +++ b/java/ql/test/query-tests/security/CWE-918/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/javax-validation-constraints:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf +//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/javax-validation-constraints:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/apache-http-fluent-4.5.14:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf diff --git a/java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java b/java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java new file mode 100644 index 000000000000..2722b480c0c6 --- /dev/null +++ b/java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java @@ -0,0 +1,26 @@ +// Generated automatically from org.apache.http.client.fluent.Request for testing purposes + +package org.apache.http.client.fluent; + +import java.net.URI; + +public class Request { + protected Request() {} + + public static Request Delete(String p0) { return null; } + public static Request Delete(URI p0) { return null; } + public static Request Get(String p0) { return null; } + public static Request Get(URI p0) { return null; } + public static Request Head(String p0) { return null; } + public static Request Head(URI p0) { return null; } + public static Request Options(String p0) { return null; } + public static Request Options(URI p0) { return null; } + public static Request Patch(String p0) { return null; } + public static Request Patch(URI p0) { return null; } + public static Request Post(String p0) { return null; } + public static Request Post(URI p0) { return null; } + public static Request Put(String p0) { return null; } + public static Request Put(URI p0) { return null; } + public static Request Trace(String p0) { return null; } + public static Request Trace(URI p0) { return null; } +} From 043ec857ab94007f495f93d5bfef5c520cc008ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 6 May 2026 20:31:34 +0000 Subject: [PATCH 3/3] Replace fluent SSRF changes with Apache HttpClient execute model tests Agent-Logs-Url: https://github.com/github/codeql/sessions/3db201db-a1b5-4353-a94a-14a8d156dd3b Co-authored-by: owen-mc <62447351+owen-mc@users.noreply.github.com> --- .../lib/ext/org.apache.http.client.model.yml | 7 ++- .../CWE-918/ApacheHttpClientExecuteSSRF.java | 43 +++++++++++++++++++ .../CWE-918/ApacheHttpFluentSSRF.java | 40 ----------------- .../test/query-tests/security/CWE-918/options | 2 +- .../org/apache/http/client/HttpClient.java | 23 ++++++++++ .../apache/http/client/ResponseHandler.java | 9 ++++ .../apache/http/client/fluent/Request.java | 26 ----------- 7 files changed, 82 insertions(+), 68 deletions(-) create mode 100644 java/ql/test/query-tests/security/CWE-918/ApacheHttpClientExecuteSSRF.java delete mode 100644 java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java create mode 100644 java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/HttpClient.java create mode 100644 java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/ResponseHandler.java delete mode 100644 java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java diff --git a/java/ql/lib/ext/org.apache.http.client.model.yml b/java/ql/lib/ext/org.apache.http.client.model.yml index 681efdf32e7c..caba9bd718b2 100644 --- a/java/ql/lib/ext/org.apache.http.client.model.yml +++ b/java/ql/lib/ext/org.apache.http.client.model.yml @@ -3,6 +3,11 @@ extensions: pack: codeql/java-all extensible: sinkModel data: + - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest)", "", "Argument[0]", "request-forgery", "ai-manual"] + - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"] + - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest,ResponseHandler)", "", "Argument[0]", "request-forgery", "ai-manual"] + - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest,ResponseHandler,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"] + - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest)", "", "Argument[0]", "request-forgery", "ai-manual"] - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"] + - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,ResponseHandler)", "", "Argument[0]", "request-forgery", "ai-manual"] - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,ResponseHandler,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"] - - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest)", "", "Argument[0]", "request-forgery", "ai-manual"] diff --git a/java/ql/test/query-tests/security/CWE-918/ApacheHttpClientExecuteSSRF.java b/java/ql/test/query-tests/security/CWE-918/ApacheHttpClientExecuteSSRF.java new file mode 100644 index 000000000000..05d38b2b5dd1 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-918/ApacheHttpClientExecuteSSRF.java @@ -0,0 +1,43 @@ +import java.io.IOException; + +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHttpRequest; +import org.apache.http.protocol.HttpContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class ApacheHttpClientExecuteSSRF extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + try { + + String sink = request.getParameter("host"); // $ Source + + HttpHost host = new HttpHost(sink); + HttpRequest req = new BasicHttpRequest("GET", "/"); + HttpUriRequest uriReq = (HttpUriRequest) (Object) sink; + HttpContext context = null; + HttpClient client = null; + ResponseHandler handler = null; + + client.execute(host, req); // $ Alert + client.execute(host, req, context); // $ Alert + client.execute(host, req, handler); // $ Alert + client.execute(host, req, handler, context); // $ Alert + client.execute(uriReq); // $ Alert + client.execute(uriReq, context); // $ Alert + client.execute(uriReq, handler); // $ Alert + client.execute(uriReq, handler, context); // $ Alert + + } catch (Exception e) { + // TODO: handle exception + } + } +} diff --git a/java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java b/java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java deleted file mode 100644 index df765ea060bd..000000000000 --- a/java/ql/test/query-tests/security/CWE-918/ApacheHttpFluentSSRF.java +++ /dev/null @@ -1,40 +0,0 @@ -import java.io.IOException; -import java.net.URI; - -import org.apache.http.client.fluent.Request; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class ApacheHttpFluentSSRF extends HttpServlet { - - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - try { - - String sink = request.getParameter("uri"); // $ Source - URI uri = new URI(sink); - - Request.Delete(sink); // $ Alert - Request.Delete(uri); // $ Alert - Request.Get(sink); // $ Alert - Request.Get(uri); // $ Alert - Request.Head(sink); // $ Alert - Request.Head(uri); // $ Alert - Request.Options(sink); // $ Alert - Request.Options(uri); // $ Alert - Request.Patch(sink); // $ Alert - Request.Patch(uri); // $ Alert - Request.Post(sink); // $ Alert - Request.Post(uri); // $ Alert - Request.Put(sink); // $ Alert - Request.Put(uri); // $ Alert - Request.Trace(sink); // $ Alert - Request.Trace(uri); // $ Alert - - } catch (Exception e) { - // TODO: handle exception - } - } -} diff --git a/java/ql/test/query-tests/security/CWE-918/options b/java/ql/test/query-tests/security/CWE-918/options index 04f8cec9345c..a5b2bf58d434 100644 --- a/java/ql/test/query-tests/security/CWE-918/options +++ b/java/ql/test/query-tests/security/CWE-918/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/javax-validation-constraints:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/apache-http-fluent-4.5.14:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf +//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/javax-validation-constraints:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/apache-http-client-4.4.13:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf diff --git a/java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/HttpClient.java b/java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/HttpClient.java new file mode 100644 index 000000000000..3cd8e33ab5c5 --- /dev/null +++ b/java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/HttpClient.java @@ -0,0 +1,23 @@ +// Generated automatically from org.apache.http.client.HttpClient for testing purposes + +package org.apache.http.client; + +import java.io.IOException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.protocol.HttpContext; + +public interface HttpClient { + HttpResponse execute(HttpHost target, HttpRequest request) throws IOException; + HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException; + T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler) throws IOException; + T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler, HttpContext context) + throws IOException; + HttpResponse execute(HttpUriRequest request) throws IOException; + HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException; + T execute(HttpUriRequest request, ResponseHandler responseHandler) throws IOException; + T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) + throws IOException; +} diff --git a/java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/ResponseHandler.java b/java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/ResponseHandler.java new file mode 100644 index 000000000000..0733cae3baf8 --- /dev/null +++ b/java/ql/test/stubs/apache-http-client-4.4.13/org/apache/http/client/ResponseHandler.java @@ -0,0 +1,9 @@ +// Generated automatically from org.apache.http.client.ResponseHandler for testing purposes + +package org.apache.http.client; + +import org.apache.http.HttpResponse; + +public interface ResponseHandler { + T handleResponse(HttpResponse response); +} diff --git a/java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java b/java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java deleted file mode 100644 index 2722b480c0c6..000000000000 --- a/java/ql/test/stubs/apache-http-fluent-4.5.14/org/apache/http/client/fluent/Request.java +++ /dev/null @@ -1,26 +0,0 @@ -// Generated automatically from org.apache.http.client.fluent.Request for testing purposes - -package org.apache.http.client.fluent; - -import java.net.URI; - -public class Request { - protected Request() {} - - public static Request Delete(String p0) { return null; } - public static Request Delete(URI p0) { return null; } - public static Request Get(String p0) { return null; } - public static Request Get(URI p0) { return null; } - public static Request Head(String p0) { return null; } - public static Request Head(URI p0) { return null; } - public static Request Options(String p0) { return null; } - public static Request Options(URI p0) { return null; } - public static Request Patch(String p0) { return null; } - public static Request Patch(URI p0) { return null; } - public static Request Post(String p0) { return null; } - public static Request Post(URI p0) { return null; } - public static Request Put(String p0) { return null; } - public static Request Put(URI p0) { return null; } - public static Request Trace(String p0) { return null; } - public static Request Trace(URI p0) { return null; } -}