Keycloak: keycloak: denial of service due to excessive samlrequest decompression
Description
A flaw was found in Keycloak. An unauthenticated remote attacker can trigger an application level Denial of Service (DoS) by sending a highly compressed SAMLRequest through the SAML Redirect Binding. The server fails to enforce size limits during DEFLATE decompression, leading to an OutOfMemoryError (OOM) and subsequent process termination. This vulnerability allows an attacker to disrupt the availability of the service.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2026-2575 is an application-level DoS in Keycloak where an unauthenticated attacker sends a highly compressed SAMLRequest via SAML Redirect Binding, causing OutOfMemoryError from unbounded DEFLATE decompression.
Vulnerability
Description
CVE-2026-2575 describes a denial of service flaw in Keycloak's SAML request handling. The root cause is the absence of size limits during DEFLATE decompression of SAML requests received via the SAML Redirect Binding. When the server processes a highly compressed SAMLRequest, the decompression operation can expand to an arbitrarily large size, exhausting available memory and triggering an OutOfMemoryError (OOM), which terminates the process and disrupts service availability [1][2].
Exploitation
Method
An unauthenticated remote attacker can exploit this vulnerability by sending a crafted SAMLRequest with a high compression ratio through the SAML Redirect Binding. No authentication or prior knowledge is required; the attack vector is network-based and targets the SAML endpoint. The server fails to enforce any bounds on the inflated data size, allowing a small network payload to cause disproportionate memory consumption [1][3].
Impact
Successful exploitation results in a complete denial of service (DoS) of the Keycloak instance. The application-level OOM crash renders the authentication service unavailable, potentially affecting all downstream applications relying on Keycloak for identity and access management. This can lead to significant business disruption [1][2].
Mitigation
Red Hat has released patches for Keycloak 26.4.10 via RHSA-2026:3948, which includes a fix that limits the maximum inflating size during SAML redirect binding decoding, as shown in the commit that introduces a configurable maxInflatingSize parameter [3][4]. Users are strongly advised to update to the latest patched version. No workaround is mentioned, so upgrading is the recommended course of action.
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.keycloak:keycloak-saml-adapter-coreMaven | < 26.5.4 | 26.5.4 |
org.keycloak:keycloak-saml-coreMaven | < 26.5.4 | 26.5.4 |
org.keycloak:keycloak-servicesMaven | < 26.5.4 | 26.5.4 |
Affected products
2- Red Hat/Red Hat build of Keycloak 26.4.10v5cpe:/a:redhat:build_keycloak:26.4::el9
Patches
14f90ef67f698Limit the inflating size for the SAML redirect binding
11 files changed · +230 −55
adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java+5 −2 modified@@ -76,6 +76,7 @@ import org.keycloak.saml.common.exceptions.ProcessingException; import org.keycloak.saml.common.util.DocumentUtil; import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature; +import org.keycloak.saml.processing.api.util.DeflateUtil; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil; import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator; @@ -100,6 +101,8 @@ */ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthenticationHandler { + public static final String MAX_INFLAFING_SIZE_PROP = "org.keycloak.adapters.saml.maxInflatingSize"; + private static final long MAX_INFLAFING_SIZE = Long.getLong(MAX_INFLAFING_SIZE_PROP, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); protected static Logger log = Logger.getLogger(WebBrowserSsoAuthenticationHandler.class); protected final HttpFacade facade; @@ -177,7 +180,7 @@ protected AuthOutcome handleSamlRequest(String samlRequest, String relayState) { if (index > -1) { requestUri = requestUri.substring(0, index); } - holder = SAMLRequestParser.parseRequestRedirectBinding(samlRequest); + holder = SAMLRequestParser.parseRequestRedirectBinding(samlRequest, MAX_INFLAFING_SIZE); } else { postBinding = true; holder = SAMLRequestParser.parseRequestPostBinding(samlRequest); @@ -634,7 +637,7 @@ protected AuthOutcome handleLogoutResponse(SAMLDocumentHolder holder, StatusResp } protected SAMLDocumentHolder extractRedirectBindingResponse(String response) { - return SAMLRequestParser.parseRequestRedirectBinding(response); + return SAMLRequestParser.parseRequestRedirectBinding(response, MAX_INFLAFING_SIZE); }
docs/documentation/topics/templates/document-attributes.adoc+1 −0 modified@@ -99,6 +99,7 @@ :upgradingguide_link: {project_doc_base_url}/upgrading/ :upgradingguide_link_latest: {project_doc_base_url_latest}/upgrading/ :upgradingclientlibs_link: https://www.keycloak.org/securing-apps/upgrading +:saml_galleon_layers_link: https://www.keycloak.org/securing-apps/saml-galleon-layers :upgradingclientlibs_name: Upgrading {project_name} Client libraries :releasenotes_name: Release Notes :releasenotes_name_short: {releasenotes_name}
docs/documentation/upgrading/topics/changes/changes-26_5_4.adoc+12 −0 modified@@ -21,3 +21,15 @@ It also lists significant changes to internal APIs. In version 26.4.0, the `server-info` endpoint changed to just return the system information for administrators in the admin realm. Nevertheless, the version property was detected to be needed by some products that interact with {project_name}. Now that property is included for administrators in the realm with permission `manage-realm`. The workaround of the `view-system` permission is more restricted too. It can only be assigned by administrators in the master realm using link:{adminguide_link}#_fine_grained_permissions[FGAP]. This permission will be deleted in a future version. + +=== Maximum inflating size for the SAML redirect binding + +Since this release, the {project_name} SAML implementation limits the data that can be inflated through the `REDIRECT` binding. The default maximum size is 128KB, the decompression stops when that value is exceeded and returns an error. The option `spi-login-protocol--saml--max-inflating-size` can be used to increase the default limit. + +.Increasing limit to 512KB +[source,bash] +---- +bin/kc.[sh|bat] --spi-login-protocol--saml--max-inflating-size=524288 +---- + +The same restriction is applied for the link:{saml_galleon_layers_link}[{project_name} SAML Galleon feature pack]. Although, in this case, you need to add a system property to the Wildfly/EAP server to change the default maximum size: `-Dorg.keycloak.adapters.saml.maxInflatingSize=524288`.
saml-core/src/main/java/org/keycloak/saml/processing/api/util/DeflateUtil.java+93 −1 modified@@ -35,6 +35,15 @@ */ public class DeflateUtil { + /** + * Maximum size for inflating. Default is 128KB like quarkus.http.limits.max-form-attribute-size. + */ + public static long DEFAULT_MAX_INFLATING_SIZE = 131072; + + private DeflateUtil() { + // utility class + } + /** * Apply DEFLATE encoding * @@ -75,7 +84,90 @@ public static byte[] encode(String message) throws IOException { * @return */ public static InputStream decode(byte[] msgToDecode) { + return decode(msgToDecode, DEFAULT_MAX_INFLATING_SIZE); + } + + /** + * DEFLATE decoding + * + * @param msgToDecode the message that needs decoding + * @param maxInflatingSize the maximum size to inflate, IOExceptio is thrown if more data is inflated + * + * @return + */ + public static InputStream decode(byte[] msgToDecode, long maxInflatingSize) { ByteArrayInputStream bais = new ByteArrayInputStream(msgToDecode); - return new InflaterInputStream(bais, new Inflater(true)); + return new LimitedInflaterInputStream(bais, maxInflatingSize); + } + + private static class LimitedInflaterInputStream extends InputStream { + + private final InflaterInputStream is; + private final Inflater inflater; + private final long maxInflatingSize; + + private LimitedInflaterInputStream(InputStream is, long maxInflatingSize) { + this.inflater = new Inflater(true); + this.is = new InflaterInputStream(is, inflater); + this.maxInflatingSize = maxInflatingSize; + } + + private void checkMaxInflatingsize() throws IOException { + if (inflater.getBytesWritten() > maxInflatingSize) { + throw new IOException(String.format("Maximum inflating size %d reached. Total bytes witten %d.", + maxInflatingSize, inflater.getTotalOut())); + } + } + + @Override + public int read() throws IOException { + int result = is.read(); + checkMaxInflatingsize(); + return result; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int result = is.read(b, off, len); + checkMaxInflatingsize(); + return result; + } + + @Override + public int read(byte[] b) throws IOException { + int result = is.read(b); + checkMaxInflatingsize(); + return result; + } + + @Override + public boolean markSupported() { + return false; + } + + @Override + public void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + @Override + public void mark(int readlimit) { + // nothing + } + + @Override + public void close() throws IOException { + is.close(); + } + + @Override + public int available() throws IOException { + return is.available(); + } + + @Override + public long skip(long n) throws IOException { + return is.skip(n); + } } } \ No newline at end of file
saml-core/src/main/java/org/keycloak/saml/processing/web/util/RedirectBindingUtil.java+30 −2 modified@@ -152,8 +152,22 @@ public static String deflateBase64Encode(byte[] stringToEncode) throws IOExcepti * @throws IOException */ public static InputStream urlBase64DeflateDecode(String encodedString) throws IOException { + return urlBase64DeflateDecode(encodedString, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } + + /** + * Apply URL decoding, followed by base64 decoding followed by deflate decompression + * + * @param encodedString + * @param maxInflatingSize + * + * @return + * + * @throws IOException + */ + public static InputStream urlBase64DeflateDecode(String encodedString, long maxInflatingSize) throws IOException { byte[] deflatedString = urlBase64Decode(encodedString); - return DeflateUtil.decode(deflatedString); + return DeflateUtil.decode(deflatedString, maxInflatingSize); } /** @@ -166,8 +180,22 @@ public static InputStream urlBase64DeflateDecode(String encodedString) throws IO * @throws IOException */ public static InputStream base64DeflateDecode(String encodedString) throws IOException { + return base64DeflateDecode(encodedString, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } + + /** + * Base64 decode followed by Deflate decoding + * + * @param encodedString + * @param maxInflatingSize + * + * @return + * + * @throws IOException + */ + public static InputStream base64DeflateDecode(String encodedString, long maxInflatingSize) throws IOException { byte[] base64decodedMsg = Base64.getMimeDecoder().decode(encodedString); - return DeflateUtil.decode(base64decodedMsg); + return DeflateUtil.decode(base64decodedMsg, maxInflatingSize); } /**
saml-core/src/main/java/org/keycloak/saml/SAMLRequestParser.java+24 −40 modified@@ -18,7 +18,6 @@ package org.keycloak.saml; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; import org.keycloak.common.util.StreamUtil; @@ -27,6 +26,7 @@ import org.keycloak.saml.common.constants.GeneralConstants; import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response; +import org.keycloak.saml.processing.api.util.DeflateUtil; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.web.util.PostBindingUtil; import org.keycloak.saml.processing.web.util.RedirectBindingUtil; @@ -42,26 +42,17 @@ public class SAMLRequestParser { protected static Logger log = Logger.getLogger(SAMLRequestParser.class); public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage) { - InputStream is; - try { - is = RedirectBindingUtil.base64DeflateDecode(samlMessage); - } catch (IOException e) { - logger.samlBase64DecodingError(e); - return null; - } - if (log.isDebugEnabled()) { - String message = null; - try { - message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); - } catch (IOException e) { - throw new RuntimeException(e); - } - log.debug("SAML Redirect Binding"); - log.debug(message); - is = new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET)); + return parseRequestRedirectBinding(samlMessage, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } - } - try { + public static SAMLDocumentHolder parseRequestRedirectBinding(String samlMessage, long maxInflatingSize) { + try (InputStream is = RedirectBindingUtil.base64DeflateDecode(samlMessage, maxInflatingSize)) { + if (log.isDebugEnabled()) { + String message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); + log.debug("SAML Redirect Binding"); + log.debug(message); + return SAML2Request.getSAML2ObjectFromStream(new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET))); + } return SAML2Request.getSAML2ObjectFromStream(is); } catch (Exception e) { logger.samlBase64DecodingError(e); @@ -110,27 +101,20 @@ public static SAMLDocumentHolder parseResponseDocument(byte[] samlBytes) { } public static SAMLDocumentHolder parseResponseRedirectBinding(String samlMessage) { - InputStream is; - try { - is = RedirectBindingUtil.base64DeflateDecode(samlMessage); - } catch (IOException e) { - logger.samlBase64DecodingError(e); - return null; - } - if (log.isDebugEnabled()) { - String message = null; - try { - message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); - } catch (IOException e) { - throw new RuntimeException(e); - } - log.debug("SAML Redirect Binding"); - log.debug(message); - is = new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET)); + return parseResponseRedirectBinding(samlMessage, DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); + } - } - SAML2Response response = new SAML2Response(); - try { + public static SAMLDocumentHolder parseResponseRedirectBinding(String samlMessage, long maxInflatingSize) { + try (InputStream is = RedirectBindingUtil.base64DeflateDecode(samlMessage, maxInflatingSize)) { + if (log.isDebugEnabled()) { + String message = StreamUtil.readString(is, GeneralConstants.SAML_CHARSET); + log.debug("SAML Redirect Binding"); + log.debug(message); + SAML2Response response = new SAML2Response(); + response.getSAML2ObjectFromStream(new ByteArrayInputStream(message.getBytes(GeneralConstants.SAML_CHARSET))); + return response.getSamlDocumentHolder(); + } + SAML2Response response = new SAML2Response(); response.getSAML2ObjectFromStream(is); return response.getSamlDocumentHolder(); } catch (Exception e) {
services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java+12 −2 modified@@ -91,6 +91,7 @@ import org.keycloak.protocol.saml.SamlMetadataPublicKeyLoader; import org.keycloak.protocol.saml.SamlPrincipalType; import org.keycloak.protocol.saml.SamlProtocol; +import org.keycloak.protocol.saml.SamlProtocolFactory; import org.keycloak.protocol.saml.SamlProtocolUtils; import org.keycloak.protocol.saml.SamlService; import org.keycloak.protocol.saml.SamlSessionUtils; @@ -154,6 +155,7 @@ public class SAMLEndpoint { protected final KeycloakSession session; protected final ClientConnection clientConnection; protected final HttpHeaders headers; + protected final long maxInflatingSize; public SAMLEndpoint(KeycloakSession session, SAMLIdentityProvider provider, SAMLIdentityProviderConfig config, UserAuthenticationIdentityProvider.AuthenticationCallback callback, DestinationValidator destinationValidator) { @@ -165,6 +167,8 @@ public SAMLEndpoint(KeycloakSession session, SAMLIdentityProvider provider, SAML this.session = session; this.clientConnection = session.getContext().getConnection(); this.headers = session.getContext().getRequestHeaders(); + SamlProtocolFactory factory = (SamlProtocolFactory) session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, SamlProtocol.LOGIN_PROTOCOL); + this.maxInflatingSize = factory.getMaxInflatingSize(); } @GET @@ -298,6 +302,12 @@ public Response execute(String samlRequest, String samlResponse, String samlArt, protected Response handleSamlRequest(String samlRequest, String relayState) { SAMLDocumentHolder holder = extractRequestDocument(samlRequest); + if (holder == null) { + event.event(EventType.IDENTITY_PROVIDER_RESPONSE); + event.detail(Details.REASON, Errors.INVALID_SAML_DOCUMENT); + event.error(Errors.INVALID_REQUEST); + return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_REQUEST); + } RequestAbstractType requestAbstractType = (RequestAbstractType) holder.getSamlObject(); // validate destination if (isDestinationRequired() && @@ -878,12 +888,12 @@ protected void verifySignature(String key, SAMLDocumentHolder documentHolder) th @Override protected SAMLDocumentHolder extractRequestDocument(String samlRequest) { - return SAMLRequestParser.parseRequestRedirectBinding(samlRequest); + return SAMLRequestParser.parseRequestRedirectBinding(samlRequest, maxInflatingSize); } @Override protected SAMLDocumentHolder extractResponseDocument(String response) { - return SAMLRequestParser.parseResponseRedirectBinding(response); + return SAMLRequestParser.parseResponseRedirectBinding(response, maxInflatingSize); } @Override
services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java+2 −2 modified@@ -59,8 +59,8 @@ public class SamlEcpProfileService extends SamlService { private static final String NS_PREFIX_SAML_PROTOCOL = "samlp"; private static final String NS_PREFIX_SAML_ASSERTION = "saml"; - public SamlEcpProfileService(KeycloakSession session, EventBuilder event, DestinationValidator destinationValidator) { - super(session, event, destinationValidator); + public SamlEcpProfileService(KeycloakSession session, EventBuilder event, long maxInflatingSize, DestinationValidator destinationValidator) { + super(session, event, maxInflatingSize, destinationValidator); } public Response authenticate(InputStream inputStream) {
services/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java+26 −1 modified@@ -40,10 +40,13 @@ import org.keycloak.protocol.saml.mappers.AttributeStatementHelper; import org.keycloak.protocol.saml.mappers.RoleListMapper; import org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.provider.ProviderConfigurationBuilder; import org.keycloak.representations.idm.CertificateRepresentation; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.saml.SignatureAlgorithm; import org.keycloak.saml.common.constants.JBossSAMLURIConstants; +import org.keycloak.saml.processing.api.util.DeflateUtil; import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants; import org.keycloak.saml.validators.DestinationValidator; @@ -57,10 +60,11 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory { private static final String ROLE_LIST_CONSENT_TEXT = "${samlRoleListScopeConsentText}"; private DestinationValidator destinationValidator; + private long maxInflatingSize; @Override public Object createProtocolEndpoint(KeycloakSession session, EventBuilder event) { - return new SamlService(session, event, destinationValidator); + return new SamlService(session, event, maxInflatingSize, destinationValidator); } @Override @@ -103,6 +107,7 @@ public void init(Config.Scope config) { defaultBuiltins.add(model); } this.destinationValidator = DestinationValidator.forProtocolMap(config.getArray("knownProtocols")); + this.maxInflatingSize = config.getLong("maxInflatingSize", DeflateUtil.DEFAULT_MAX_INFLATING_SIZE); } @Override @@ -202,4 +207,24 @@ public void setupClientDefaults(ClientRepresentation clientRep, ClientModel newC public int order() { return OIDCLoginProtocolFactory.UI_ORDER - 10; } + + /** + * Getter for the max inflating size + * @return + */ + public long getMaxInflatingSize() { + return maxInflatingSize; + } + + @Override + public List<ProviderConfigProperty> getConfigMetadata() { + return ProviderConfigurationBuilder.create() + .property() + .name("maxInflatingSize") + .type("long") + .helpText("The maximum inflating size in bytes for the REDIRECT binding.") + .defaultValue(DeflateUtil.DEFAULT_MAX_INFLATING_SIZE) + .add() + .build(); + } }
services/src/main/java/org/keycloak/protocol/saml/SamlService.java+7 −5 modified@@ -159,10 +159,12 @@ public class SamlService extends AuthorizationEndpointBase { public static final String ARTIFACT_RESOLUTION_SERVICE_PATH = "resolve"; private final DestinationValidator destinationValidator; + private final long maxInflatingSize; - public SamlService(KeycloakSession session, EventBuilder event, DestinationValidator destinationValidator) { + public SamlService(KeycloakSession session, EventBuilder event, long maxInflatingSize, DestinationValidator destinationValidator) { super(session, event); this.destinationValidator = destinationValidator; + this.maxInflatingSize = maxInflatingSize; } public abstract class BindingProtocol { @@ -204,7 +206,7 @@ protected Response handleSamlResponse(String samlResponse, String relayState) { event.event(EventType.LOGOUT); SAMLDocumentHolder holder = extractResponseDocument(samlResponse); - if (! (holder.getSamlObject() instanceof StatusResponseType)) { + if (holder == null || !(holder.getSamlObject() instanceof StatusResponseType)) { event.detail(Details.REASON, Errors.INVALID_SAML_RESPONSE); event.error(Errors.INVALID_SAML_RESPONSE); return error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_REQUEST); @@ -848,12 +850,12 @@ protected boolean containsUnencryptedSignature(SAMLDocumentHolder documentHolder @Override protected SAMLDocumentHolder extractRequestDocument(String samlRequest) { - return SAMLRequestParser.parseRequestRedirectBinding(samlRequest); + return SAMLRequestParser.parseRequestRedirectBinding(samlRequest, maxInflatingSize); } @Override protected SAMLDocumentHolder extractResponseDocument(String response) { - return SAMLRequestParser.parseResponseRedirectBinding(response); + return SAMLRequestParser.parseResponseRedirectBinding(response, maxInflatingSize); } @Override @@ -1120,7 +1122,7 @@ public Response artifactResolutionService(InputStream inputStream) { @NoCache @Consumes({"application/soap+xml",MediaType.TEXT_XML}) public Response soapBinding(InputStream inputStream) { - SamlEcpProfileService bindingService = new SamlEcpProfileService(session, event, destinationValidator); + SamlEcpProfileService bindingService = new SamlEcpProfileService(session, event, maxInflatingSize, destinationValidator); return bindingService.authenticate(inputStream); }
services/src/test/java/org/keycloak/test/broker/saml/SAMLParsingTest.java+18 −0 modified@@ -17,12 +17,14 @@ package org.keycloak.test.broker.saml; +import java.io.IOException; import java.util.Base64; import org.keycloak.saml.SAMLRequestParser; import org.keycloak.saml.common.constants.GeneralConstants; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.web.util.PostBindingUtil; +import org.keycloak.saml.processing.web.util.RedirectBindingUtil; import org.junit.Assert; import org.junit.Test; @@ -35,6 +37,7 @@ public class SAMLParsingTest { private static final String SAML_RESPONSE = "<samlp:LogoutResponse xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Destination=\"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint\" ID=\"ID_9a171d23-c417-42f5-9bca-c093123fd68c\" InResponseTo=\"ID_bc730711-2037-43f3-ad76-7bc33842fb87\" IssueInstant=\"2016-02-29T12:00:14.044Z\" Version=\"2.0\"><saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">http://localhost:8082/auth/realms/realm-with-saml-idp-basic</saml:Issuer><samlp:Status><samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\"/></samlp:Status></samlp:LogoutResponse>"; + private static final String SAML_REQUEST = "<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" AssertionConsumerServiceURL=\"http://localhost:8080/realms/master/broker/saml/endpoint\" AttributeConsumingServiceIndex=\"0\" Destination=\"http://localhost:8080/realms/saml/protocol/saml\" ForceAuthn=\"false\" ID=\"ID_7228aef5-4a58-4481-a371-30e4ad7e98f4\" IssueInstant=\"2026-02-16T11:23:32.472Z\" ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Version=\"2.0\"><saml:Issuer>http://localhost:8080/realms/master</saml:Issuer><samlp:NameIDPolicy AllowCreate=\"true\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\"/></samlp:AuthnRequest>"; @Test public void parseTest() { @@ -51,4 +54,19 @@ public void parseMimeTest() { SAMLDocumentHolder holder = SAMLRequestParser.parseResponseDocument(samlBytes); Assert.assertNotNull(holder); } + + @Test + public void parseRequestResponseRedirectBinding() throws IOException { + String encodedResponse = RedirectBindingUtil.deflateBase64Encode(SAML_RESPONSE.getBytes(GeneralConstants.SAML_CHARSET_NAME)); + SAMLDocumentHolder holder = SAMLRequestParser.parseResponseRedirectBinding(encodedResponse, SAML_RESPONSE.length()); + Assert.assertNotNull(holder); + holder = SAMLRequestParser.parseResponseRedirectBinding(encodedResponse, SAML_RESPONSE.length() - 1); + Assert.assertNull(holder); + + String encodedRequest = RedirectBindingUtil.deflateBase64Encode(SAML_REQUEST.getBytes(GeneralConstants.SAML_CHARSET_NAME)); + holder = SAMLRequestParser.parseRequestRedirectBinding(encodedRequest, SAML_REQUEST.length()); + Assert.assertNotNull(holder); + holder = SAMLRequestParser.parseRequestRedirectBinding(encodedRequest, SAML_RESPONSE.length() - 1); + Assert.assertNull(holder); + } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- access.redhat.com/errata/RHSA-2026:3947ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2026:3948ghsavendor-advisoryx_refsource_REDHATWEB
- github.com/advisories/GHSA-xv6h-r36f-3gp5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-2575ghsaADVISORY
- access.redhat.com/security/cve/CVE-2026-2575ghsavdb-entryx_refsource_REDHATWEB
- bugzilla.redhat.com/show_bug.cgighsaissue-trackingx_refsource_REDHATWEB
- github.com/keycloak/keycloak/commit/4f90ef67f698dfb45df0d2f4981271a7c8b47f04ghsaWEB
- github.com/keycloak/keycloak/issues/46372ghsaWEB
News mentions
0No linked articles in our index yet.