spring-projects/spring-security · error · IllegalArgumentException

Failed to decode SAMLResponse

Error message

Failed to decode SAMLResponse

What it means

Before base64-decoding a SAML response parameter, Saml2Utils validates the base64 string against a whitelist of acceptable characters (an EncodingConfigurer's checkAcceptable). If the string contains characters not permitted in base64, it throws IllegalArgumentException 'Failed to decode SAMLResponse' rather than producing corrupt bytes.

Source

Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2Utils.java:189

					}
				}

				// in cases of an incomplete final chunk, ensure the unused bits are zero
				switch (goodChars % 4) {
					case 0:
						return true;
					case 2:
						return (lastGoodCharVal & 0b1111) == 0;
					case 3:
						return (lastGoodCharVal & 0b11) == 0;
					default:
						return false;
				}
			}

			void checkAcceptable(String ins) {
				if (!isAcceptable(ins)) {
					throw new IllegalArgumentException("Failed to decode SAMLResponse");
				}
			}

		}

	}

	static class CappedOutputStream extends OutputStream {

		private static final long MAX_SIZE = 1024 * 1024;

		private final OutputStream delegate;

		private int size;

		CappedOutputStream(OutputStream delegate) {
			this.delegate = delegate;
		}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Ensure exactly one URL-decode of the SAMLResponse parameter before base64 decoding and no manual pre-decoding by intermediate filters.
  2. Inspect the offending parameter value (log a safe prefix) to find illegal characters such as spaces, <, >, or quotes.
  3. Read the correct request parameter name (SAMLResponse, not RelayState or SAMLRequest) in the controller/filter.
  4. If legitimate IdP payloads include characters your validator rejects (e.g. newlines), align isAcceptable() with RFC 4648 base64 plus the line-length rules you actually receive, or update Spring Security to a version with relaxed validation.
  5. Catch IllegalArgumentException around decode and respond with HTTP 400 for malformed SAML responses.

Example fix

// before
String raw = URLDecoder.decode(request.getParameter("SAMLResponse"), StandardCharsets.UTF_8);
Saml2Utils.withDecoded(raw).decode(); // IllegalArgumentException
// after
String raw = request.getParameter("SAMLResponse"); // container already URL-decodes form params
Saml2Utils.withDecoded(raw).decode();
Defensive patterns

Strategy: validation

Validate before calling

static final Pattern B64 = Pattern.compile("^[A-Za-z0-9+/=\\r\\n]+$");
boolean looksLikeBase64(String s) { return s != null && B64.matcher(s).matches(); }
if (!looksLikeBase64(request.getParameter("SAMLResponse"))) { response.sendError(400); return; }

Try / catch

try {
    byte[] decoded = Saml2Utils.withDecoded(param).decode();
} catch (IllegalArgumentException ex) {
    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "malformed SAML response");
}

Prevention

When it happens

Trigger: Passing a SAMLResponse (or SAMLRequest/SAMLLogoutRequest) parameter value to the decoder that contains non-base64 characters — e.g. raw XML, already-decoded text, HTML-escaped entities, or a value with whitespace/newlines outside the accepted set.

Common situations: The POST parameter was already URL-decoded or base64-decoded upstream (gateway, logging filter) and the mangled value is re-processed; the wrong form field is read (e.g. RelayState instead of SAMLResponse); the IdP sends content the SP's acceptable-character policy rejects; copy-pasted sample payloads in tests include line breaks or quotes.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/b8906108dcdd5de8. Report an issue: GitHub.