From 0a9b9eb22be81f5c44212609621792004a8daad2 Mon Sep 17 00:00:00 2001 From: Mohammed Hassan Date: Wed, 28 Oct 2026 15:20:22 +0530 Subject: [PATCH] reject dot-segment path parameters in RestInvocationHandler A @PathParam value of "." or ".." was appended as a literal dot segment, so once the request path is normalized the caller-supplied value moves the request out of the resource the template maps. --- .../hc/client5/http/rest/RestInvocationHandler.java | 2 ++ .../hc/client5/http/rest/RestClientBuilderTest.java | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/httpclient5-jakarta-rest-client/src/main/java/org/apache/hc/client5/http/rest/RestInvocationHandler.java b/httpclient5-jakarta-rest-client/src/main/java/org/apache/hc/client5/http/rest/RestInvocationHandler.java index c40e9829d7..5df10f7e18 100644 --- a/httpclient5-jakarta-rest-client/src/main/java/org/apache/hc/client5/http/rest/RestInvocationHandler.java +++ b/httpclient5-jakarta-rest-client/src/main/java/org/apache/hc/client5/http/rest/RestInvocationHandler.java @@ -129,6 +129,8 @@ private Object executeRequest(final ResourceMethod rm, switch (param.getType()) { case PATH: Args.check(paramValue != null, "Path parameter '%s' must not be null", param.getName()); + Args.check(!".".equals(paramValue) && !"..".equals(paramValue), + "Path parameter '%s' must not be a '.' or '..' segment", param.getName()); pathParams.put(paramName, paramValue); break; case QUERY: diff --git a/httpclient5-jakarta-rest-client/src/test/java/org/apache/hc/client5/http/rest/RestClientBuilderTest.java b/httpclient5-jakarta-rest-client/src/test/java/org/apache/hc/client5/http/rest/RestClientBuilderTest.java index 1db236e1bf..f5dc1c6713 100644 --- a/httpclient5-jakarta-rest-client/src/test/java/org/apache/hc/client5/http/rest/RestClientBuilderTest.java +++ b/httpclient5-jakarta-rest-client/src/test/java/org/apache/hc/client5/http/rest/RestClientBuilderTest.java @@ -721,6 +721,14 @@ void testNullPathParamThrows() { assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> api.echoPath(null)); } + @Test + void testDotSegmentPathParamThrows() { + final EchoPathApi api = proxy(EchoPathApi.class); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> api.echoPath("..")); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> api.echoPath(".")); + assertThat(api.echoPath("..a")).isEqualTo("..a"); + } + @Test void testQueryParamSpaceEncodedAsPercent20() { final EchoApi api = proxy(EchoApi.class);