This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new c6937f0c19 Fix security issue with malformed HTTP Method
c6937f0c19 is described below

commit c6937f0c198366ec44f3fa4ee2bf11ff485f5913
Author: James Bognar <[email protected]>
AuthorDate: Thu Dec 4 12:10:44 2025 -0800

    Fix security issue with malformed HTTP Method
---
 .../java/org/apache/juneau/rest/RestSession.java   | 12 ++++++++++-
 .../org/apache/juneau/rest/logger/CallLogger.java  |  2 +-
 .../annotation/Rest_AllowedMethodParams_Test.java  | 23 ++++++++++++++++++++++
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestSession.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestSession.java
index 18e58231b4..6be399cf59 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestSession.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestSession.java
@@ -24,6 +24,7 @@ import java.util.*;
 
 import org.apache.http.*;
 import org.apache.juneau.*;
+import org.apache.juneau.commons.utils.*;
 import org.apache.juneau.cp.*;
 import org.apache.juneau.http.response.*;
 import org.apache.juneau.rest.annotation.*;
@@ -297,12 +298,15 @@ public class RestSession extends ContextSession {
         */
        public Throwable getException() { return 
(Throwable)req.getAttribute("Exception"); }
 
+       private static AsciiSet VALID_METHOD_CHARS = 
AsciiSet.create().ranges("A-Z", "a-z" ,"0-9").chars("_-").build();
+
        /**
         * Returns the HTTP method name.
         *
         * @return The HTTP method name, always uppercased.
+        * @throws NotFound If the method parameter contains invalid/malformed 
characters.
         */
-       public String getMethod() {
+       public String getMethod() throws NotFound {
                if (method == null) {
 
                        Set<String> s1 = context.getAllowedMethodParams();
@@ -312,12 +316,18 @@ public class RestSession extends ContextSession {
                                String[] x = getQueryParams().get("method");
                                if (nn(x) && (s1.contains("*") || 
s1.contains(x[0])))
                                        method = x[0];
+                               if (method != null && ! 
VALID_METHOD_CHARS.containsOnly(method)) {
+                                       throw new MethodNotAllowed();
+                               }
                        }
 
                        if (method == null && ! s2.isEmpty()) {
                                var x = req.getHeader("X-Method");
                                if (nn(x) && (s2.contains("*") || 
s2.contains(x)))
                                        method = x;
+                               if (method != null && ! 
VALID_METHOD_CHARS.containsOnly(method)) {
+                                       throw new MethodNotAllowed();
+                               }
                        }
 
                        if (method == null)
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
index 74ed858bde..a2a71fe237 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logger/CallLogger.java
@@ -576,7 +576,7 @@ public class CallLogger {
 
                if (nn(sti)) {
                        var count = sti.getCount();
-                       
sb.append(',').append(StringUtils.toHex8(sti.getHash())).append('.').append(count);
+                       
sb.append(',').append(StringUtils.toHex8(Math.abs(sti.getHash()))).append('.').append(count);
                        if (count > 1)
                                e = null;
                }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_AllowedMethodParams_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_AllowedMethodParams_Test.java
index 895bc9b270..6e4d192193 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_AllowedMethodParams_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_AllowedMethodParams_Test.java
@@ -165,4 +165,27 @@ class Rest_AllowedMethodParams_Test extends TestBase {
                a8.get("/?method=OPTIONS").run().assertContent("GET");
                a8.request("get","/?method=FOO").run().assertContent("GET");
        }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Security: Malformed method parameters should return 405, not 500 
(CWE-74)
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test void b01_malformedMethodParameter_returns405() throws Exception {
+               var a5 = MockRestClient.build(A5.class);
+
+               // Test various malformed method parameters that should return 
404
+               // These contain special characters that indicate 
malformed/encoded input
+               
a5.get("/?method=VIEW%5C%5C%5C%22&noTrace=true").ignoreErrors().run().assertStatus(405);
+               
a5.get("/?method=VIEW\\\"&noTrace=true").ignoreErrors().run().assertStatus(405);
+               
a5.get("/?method=VIEW%22&noTrace=true").ignoreErrors().run().assertStatus(405);
+               
a5.get("/?method=VIEW<script>&noTrace=true").ignoreErrors().run().assertStatus(405);
+               
a5.get("/?method=VIEW/test&noTrace=true").ignoreErrors().run().assertStatus(405);
+               
a5.get("/?method=VIEW%2Ftest&noTrace=true").ignoreErrors().run().assertStatus(405);
+               // Test with spaces and other invalid characters
+               a5.get("/?method=VIEW 
test&noTrace=true").ignoreErrors().run().assertStatus(405);
+               
a5.get("/?method=VIEW+test&noTrace=true").ignoreErrors().run().assertStatus(405);
+               // Valid method parameters should still work
+               a5.get("/?method=VIEW").ignoreErrors().run().assertStatus(405); 
// 405 because VIEW method doesn't exist, but not 500
+               a5.get("/?method=FOO").run().assertContent("FOO"); // Valid 
method works
+       }
 }
\ No newline at end of file

Reply via email to