From 29a470ed33d486efe6544d83e0b1952a6f72b99e Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:43:18 -0800 Subject: [PATCH 1/3] fix vulnerability where all headers are passed on redirect --- .../http/middleware/RedirectHandler.java | 5 ++- .../http/middleware/RedirectHandlerTests.java | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/RedirectHandler.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/RedirectHandler.java index 4cc2d4c9a..ff2a7862b 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/RedirectHandler.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/RedirectHandler.java @@ -111,8 +111,11 @@ Request getRedirect(final Request request, final Response userResponse) boolean sameScheme = locationUrl.scheme().equalsIgnoreCase(requestUrl.scheme()); boolean sameHost = locationUrl.host().toString().equalsIgnoreCase(requestUrl.host().toString()); - if (!sameScheme || !sameHost) { + boolean samePort = locationUrl.port() == requestUrl.port(); + if (!sameScheme || !sameHost || !samePort) { requestBuilder.removeHeader("Authorization"); + requestBuilder.removeHeader("Cookie"); + requestBuilder.removeHeader("Proxy-Authorization"); } // Response status code 303 See Other then POST changes to GET diff --git a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java index e72a3fafc..27e8cf8e8 100644 --- a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java +++ b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java @@ -1,6 +1,8 @@ package com.microsoft.kiota.http.middleware; +import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import com.microsoft.kiota.http.KiotaClientFactory; import com.microsoft.kiota.http.middleware.options.RedirectHandlerOption; @@ -8,6 +10,7 @@ import okhttp3.*; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.Test; @@ -54,4 +57,45 @@ void redirectsCanBeDisabled() throws Exception { assertEquals(301, response.code()); } + + @Test + void crossHostRedirectLeaksCookies() throws Exception { + Request original = new Request.Builder() + .url("http://trusted.example.com/api") + .addHeader("Authorization", "Bearer token") + .addHeader("Cookie", "session=SECRET") + .addHeader("Proxy-Authorization", "Basic cHJveHk6cGFzcw==") + .build(); + Response redirect = new Response.Builder() + .request(original).protocol(Protocol.HTTP_1_1) + .code(302).message("Found") + .header("Location", "http://evil.attacker.com/steal") + .body(ResponseBody.create("", MediaType.parse("text/plain"))) + .build(); + Request result = new RedirectHandler().getRedirect(original, redirect); + assertNotNull(result); + assertEquals("evil.attacker.com", result.url().host()); + assertNull(result.header("Authorization")); // stripped (good) + assertNull(result.header("Cookie")); // stripped (good) + assertNull(result.header("Proxy-Authorization")); // stripped (good) + } + + @Test + void endToEndProof() throws Exception { + var evil = new MockWebServer(); + evil.start(); + evil.enqueue(new MockResponse().setResponseCode(200)); + var trusted = new MockWebServer(); + trusted.start(); + trusted.enqueue(new MockResponse().setResponseCode(302) + .setHeader("Location", evil.url("/steal"))); + OkHttpClient client = KiotaClientFactory.create(new Interceptor[]{new RedirectHandler()}).build(); + client.newCall(new Request.Builder().url(trusted.url("/api")).addHeader("Cookie", "session=SECRET").build()).execute(); + trusted.takeRequest(); + RecordedRequest captured = evil.takeRequest(); + assertNull(captured.getHeader("Cookie")); + evil.shutdown(); + trusted.shutdown(); + } + } From 5364a519bcff22e235942495dba5187aae9a5be0 Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:12:16 -0800 Subject: [PATCH 2/3] formatting --- .../http/middleware/RedirectHandlerTests.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java index 27e8cf8e8..a88628651 100644 --- a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java +++ b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java @@ -60,18 +60,22 @@ void redirectsCanBeDisabled() throws Exception { @Test void crossHostRedirectLeaksCookies() throws Exception { - Request original = new Request.Builder() - .url("http://trusted.example.com/api") - .addHeader("Authorization", "Bearer token") - .addHeader("Cookie", "session=SECRET") - .addHeader("Proxy-Authorization", "Basic cHJveHk6cGFzcw==") - .build(); - Response redirect = new Response.Builder() - .request(original).protocol(Protocol.HTTP_1_1) - .code(302).message("Found") - .header("Location", "http://evil.attacker.com/steal") - .body(ResponseBody.create("", MediaType.parse("text/plain"))) - .build(); + Request original = + new Request.Builder() + .url("http://trusted.example.com/api") + .addHeader("Authorization", "Bearer token") + .addHeader("Cookie", "session=SECRET") + .addHeader("Proxy-Authorization", "Basic cHJveHk6cGFzcw==") + .build(); + Response redirect = + new Response.Builder() + .request(original) + .protocol(Protocol.HTTP_1_1) + .code(302) + .message("Found") + .header("Location", "http://evil.attacker.com/steal") + .body(ResponseBody.create("", MediaType.parse("text/plain"))) + .build(); Request result = new RedirectHandler().getRedirect(original, redirect); assertNotNull(result); assertEquals("evil.attacker.com", result.url().host()); @@ -87,15 +91,20 @@ void endToEndProof() throws Exception { evil.enqueue(new MockResponse().setResponseCode(200)); var trusted = new MockWebServer(); trusted.start(); - trusted.enqueue(new MockResponse().setResponseCode(302) - .setHeader("Location", evil.url("/steal"))); - OkHttpClient client = KiotaClientFactory.create(new Interceptor[]{new RedirectHandler()}).build(); - client.newCall(new Request.Builder().url(trusted.url("/api")).addHeader("Cookie", "session=SECRET").build()).execute(); + trusted.enqueue( + new MockResponse().setResponseCode(302).setHeader("Location", evil.url("/steal"))); + OkHttpClient client = + KiotaClientFactory.create(new Interceptor[] {new RedirectHandler()}).build(); + client.newCall( + new Request.Builder() + .url(trusted.url("/api")) + .addHeader("Cookie", "session=SECRET") + .build()) + .execute(); trusted.takeRequest(); RecordedRequest captured = evil.takeRequest(); - assertNull(captured.getHeader("Cookie")); + assertNull(captured.getHeader("Cookie")); evil.shutdown(); trusted.shutdown(); } - } From 026aaceb108730de3a74db9ea357b0d5dc7e9d8a Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:15:40 -0800 Subject: [PATCH 3/3] remove test secret --- .../microsoft/kiota/http/middleware/RedirectHandlerTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java index a88628651..e07e533ed 100644 --- a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java +++ b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java @@ -65,7 +65,7 @@ void crossHostRedirectLeaksCookies() throws Exception { .url("http://trusted.example.com/api") .addHeader("Authorization", "Bearer token") .addHeader("Cookie", "session=SECRET") - .addHeader("Proxy-Authorization", "Basic cHJveHk6cGFzcw==") + .addHeader("Proxy-Authorization", "Basic ") .build(); Response redirect = new Response.Builder()