From 8986a1b944deab3c70a8e80c400b46f50ba038a1 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Sun, 14 Jun 2026 16:19:49 +0000 Subject: [PATCH] Java: Add URLEncoder.encode() sanitizer and exclude tests from java/log-injection --- .../semmle/code/java/security/LogInjection.qll | 16 ++++++++++++++++ java/ql/src/Security/CWE/CWE-117/LogInjection.ql | 6 +++++- ...-06-14-log-injection-url-encoder-sanitizer.md | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 java/ql/src/change-notes/2026-06-14-log-injection-url-encoder-sanitizer.md diff --git a/java/ql/lib/semmle/code/java/security/LogInjection.qll b/java/ql/lib/semmle/code/java/security/LogInjection.qll index b585c249d1eb..3d58041f8799 100644 --- a/java/ql/lib/semmle/code/java/security/LogInjection.qll +++ b/java/ql/lib/semmle/code/java/security/LogInjection.qll @@ -36,6 +36,22 @@ private class DefaultLogInjectionSink extends LogInjectionSink { private class DefaultLogInjectionSanitizer extends LogInjectionSanitizer instanceof SimpleTypeSanitizer { } +/** + * A call to `URLEncoder.encode()`, considered as a sanitizer. + * + * URL encoding replaces newline characters with `%0A` and `%0D`, + * which prevents log injection. + */ +private class UrlEncoderSanitizer extends LogInjectionSanitizer { + UrlEncoderSanitizer() { + exists(MethodCall mc | + mc.getMethod().getDeclaringType().hasQualifiedName("java.net", "URLEncoder") and + mc.getMethod().hasName("encode") and + this.asExpr() = mc + ) + } +} + private class LineBreaksLogInjectionSanitizer extends LogInjectionSanitizer { LineBreaksLogInjectionSanitizer() { logInjectionSanitizer(this.asExpr()) diff --git a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql index f3efb578f76a..c78b3b5ea05e 100644 --- a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql +++ b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql @@ -14,8 +14,12 @@ import java import semmle.code.java.security.LogInjectionQuery import LogInjectionFlow::PathGraph +private import semmle.code.java.dataflow.internal.ModelExclusions from LogInjectionFlow::PathNode source, LogInjectionFlow::PathNode sink -where LogInjectionFlow::flowPath(source, sink) +where + LogInjectionFlow::flowPath(source, sink) and + // Exclude sinks in test files - log injection in tests is not a real vulnerability. + not isInTestFile(sink.getNode().asExpr().getFile()) select sink.getNode(), source, sink, "This log entry depends on a $@.", source.getNode(), "user-provided value" diff --git a/java/ql/src/change-notes/2026-06-14-log-injection-url-encoder-sanitizer.md b/java/ql/src/change-notes/2026-06-14-log-injection-url-encoder-sanitizer.md new file mode 100644 index 000000000000..f0564bc107fd --- /dev/null +++ b/java/ql/src/change-notes/2026-06-14-log-injection-url-encoder-sanitizer.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- + +* The `java/log-injection` query now recognizes `URLEncoder.encode()` as a sanitizer, since URL encoding replaces newline characters with percent-encoded sequences (`%0A`, `%0D`), preventing log injection. Results in test files are also excluded. This reduces false positives when user-controlled values are URL-encoded before logging.