From b76eb281890d8966d3edbf223b40803d39de8313 Mon Sep 17 00:00:00 2001 From: Javid Khan Date: Tue, 28 Jul 2026 12:23:19 +0530 Subject: [PATCH] reject control characters in bearer token in BearerScheme --- .../client5/http/impl/auth/BearerScheme.java | 8 +++++++- .../http/impl/auth/TestBearerScheme.java | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BearerScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BearerScheme.java index 9ee4c70858..7dc105498f 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BearerScheme.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BearerScheme.java @@ -160,7 +160,13 @@ public String generateAuthResponse( final HttpRequest request, final HttpContext context) throws AuthenticationException { Asserts.notNull(bearerToken, "Bearer token"); - return StandardAuthScheme.BEARER + " " + bearerToken.getToken(); + final String token = bearerToken.getToken(); + for (int i = 0; i < token.length(); i++) { + if (Character.isISOControl(token.charAt(i))) { + throw new AuthenticationException("Bearer token must not contain any control characters"); + } + } + return StandardAuthScheme.BEARER + " " + token; } @Override diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBearerScheme.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBearerScheme.java index a2ebdea344..5bdeb633cc 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBearerScheme.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBearerScheme.java @@ -29,6 +29,7 @@ import org.apache.hc.client5.http.auth.AuthChallenge; import org.apache.hc.client5.http.auth.AuthScheme; import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.AuthenticationException; import org.apache.hc.client5.http.auth.BearerToken; import org.apache.hc.client5.http.auth.ChallengeType; import org.apache.hc.client5.http.auth.CredentialsProvider; @@ -74,6 +75,25 @@ void testBearerAuthentication() throws Exception { Assertions.assertFalse(authscheme.isConnectionBased()); } + @Test + void testBearerTokenWithControlCharacters() throws Exception { + final AuthChallenge authChallenge = new AuthChallenge(ChallengeType.TARGET, "Bearer", + new BasicNameValuePair("realm", "test")); + + final AuthScheme authscheme = new BearerScheme(); + authscheme.processChallenge(authChallenge, null); + + final HttpHost host = new HttpHost("somehost", 80); + final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create() + .add(new AuthScope(host, "test", null), new BearerToken("token\r\nX-Injected: evil")) + .build(); + + final HttpRequest request = new BasicHttpRequest("GET", "/"); + Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null)); + Assertions.assertThrows(AuthenticationException.class, + () -> authscheme.generateAuthResponse(host, request, null)); + } + @Test void testStateStorage() throws Exception { final AuthChallenge authChallenge = new AuthChallenge(ChallengeType.TARGET, "Bearer",