diff --git a/components/identity-core/org.wso2.carbon.identity.core/pom.xml b/components/identity-core/org.wso2.carbon.identity.core/pom.xml
index 43ce964c798d..930814a589e9 100644
--- a/components/identity-core/org.wso2.carbon.identity.core/pom.xml
+++ b/components/identity-core/org.wso2.carbon.identity.core/pom.xml
@@ -165,6 +165,18 @@
h2
test
+
+ org.apache.tomcat
+ tomcat-coyote
+ ${apache.tomcat-catalina.version}
+ test
+
+
+ org.apache.tomcat
+ tomcat-util
+ ${apache.tomcat-catalina.version}
+ test
+
diff --git a/components/identity-core/org.wso2.carbon.identity.core/src/main/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValve.java b/components/identity-core/org.wso2.carbon.identity.core/src/main/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValve.java
index 99c40a8f8eb8..1178a6990145 100644
--- a/components/identity-core/org.wso2.carbon.identity.core/src/main/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValve.java
+++ b/components/identity-core/org.wso2.carbon.identity.core/src/main/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValve.java
@@ -28,8 +28,10 @@
import org.wso2.carbon.identity.core.internal.context.OrganizationResolver;
import java.io.IOException;
+import java.util.Enumeration;
import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
public class IdentityContextCreatorValve extends ValveBase {
@@ -48,6 +50,23 @@ public IdentityContextCreatorValve() {
public void invoke(Request request, Response response) throws IOException, ServletException {
try {
+ // Enforce RFC 9110 ยง11.6.1: The Authorization header is a single-value field.
+ // Rejecting requests with multiple Authorization headers early at the transport/valve layer
+ // prevents potential header manipulation and security vulnerabilities.
+ Enumeration authHeaders = request.getHeaders("Authorization");
+ if (authHeaders != null) {
+ int authHeaderCount = 0;
+ while (authHeaders.hasMoreElements()) {
+ authHeaders.nextElement();
+ authHeaderCount++;
+ if (authHeaderCount > 1) {
+ LOG.warn("Multiple Authorization headers detected.");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Multiple Authorization headers are not allowed.");
+ return;
+ }
+ }
+ }
+
initIdentityContext();
initRequest(request);
initAccessTokenIssuedOrganization(request.getRequestURI());
diff --git a/components/identity-core/org.wso2.carbon.identity.core/src/test/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValveTest.java b/components/identity-core/org.wso2.carbon.identity.core/src/test/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValveTest.java
new file mode 100644
index 000000000000..bafdb19e7644
--- /dev/null
+++ b/components/identity-core/org.wso2.carbon.identity.core/src/test/java/org/wso2/carbon/identity/core/context/valve/IdentityContextCreatorValveTest.java
@@ -0,0 +1,83 @@
+package org.wso2.carbon.identity.core.context.valve;
+
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class IdentityContextCreatorValveTest {
+
+ private IdentityContextCreatorValve identityContextCreatorValve;
+
+ @Mock
+ private Valve nextValve;
+
+ private AutoCloseable closeable;
+
+ @BeforeMethod
+ public void setUp() {
+ System.setProperty("carbon.home", ".");
+ closeable = MockitoAnnotations.openMocks(this);
+ identityContextCreatorValve = new IdentityContextCreatorValve();
+ identityContextCreatorValve.setNext(nextValve);
+ }
+
+ @AfterMethod
+ public void tearDown() throws Exception {
+ if (closeable != null) {
+ closeable.close();
+ }
+ }
+
+ @Test
+ public void testInvokeWithMultipleAuthorizationHeaders() throws Exception {
+ Vector headers = new Vector<>();
+ headers.add("Bearer token1");
+ headers.add("Bearer token2");
+ final Enumeration headerEnum = headers.elements();
+
+ Request request = new Request(null) {
+ @Override
+ public Enumeration getHeaders(String name) {
+ if ("Authorization".equals(name)) {
+ return headerEnum;
+ }
+ return super.getHeaders(name);
+ }
+
+ @Override
+ public String getRequestURI() {
+ return "/oauth2/userinfo";
+ }
+ };
+
+ final int[] errorStatus = new int[1];
+ final String[] errorMessage = new String[1];
+ Response response = new Response() {
+ @Override
+ public void sendError(int status, String message) throws java.io.IOException {
+ errorStatus[0] = status;
+ errorMessage[0] = message;
+ }
+ };
+
+ identityContextCreatorValve.invoke(request, response);
+
+ org.testng.Assert.assertEquals(errorStatus[0], HttpServletResponse.SC_BAD_REQUEST);
+ org.testng.Assert.assertEquals(errorMessage[0], "Multiple Authorization headers are not allowed.");
+ verify(nextValve, never()).invoke(any(Request.class), any(Response.class));
+ }
+}