{"record":{"id":"04642de7dd580700","repo":"spring-projects/spring-security","slug":"saml2exception-wrapping-marshallingexception-while","errorCode":null,"errorMessage":"Saml2Exception wrapping MarshallingException while re-marshalling response after decryption","messagePattern":"Saml2Exception wrapping MarshallingException while re-marshalling response after decryption","errorType":"exception","errorClass":"Saml2Exception","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java","lineNumber":532,"sourceCode":"\t\t\t\t\t}\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t\tcatch (DecryptionException ex) {\n\t\t\t\t\tthrow new Saml2Exception(ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresponse.getAssertions().addAll(decrypteds);\n\n\t\t\t// Re-marshall the response so that any ID attributes within the decrypted\n\t\t\t// Assertions\n\t\t\t// will have their ID-ness re-established at the DOM level.\n\t\t\tif (!decrypteds.isEmpty()) {\n\t\t\t\ttry {\n\t\t\t\t\tXMLObjectSupport.marshall(response);\n\t\t\t\t}\n\t\t\t\tcatch (final MarshallingException ex) {\n\t\t\t\t\tthrow new Saml2Exception(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void decryptAssertion(Assertion assertion) {\n\t\t\tfor (AttributeStatement statement : assertion.getAttributeStatements()) {\n\t\t\t\tdecryptAttributes(statement);\n\t\t\t}\n\t\t\tdecryptSubject(assertion.getSubject());\n\t\t\tif (assertion.getConditions() != null) {\n\t\t\t\tfor (Condition c : assertion.getConditions().getConditions()) {\n\t\t\t\t\tif (!(c instanceof DelegationRestrictionType delegation)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfor (Delegate d : delegation.getDelegates()) {\n\t\t\t\t\t\tif (d.getEncryptedID() != null) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tNameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID());","sourceCodeStart":514,"sourceCodeEnd":550,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java#L514-L550","documentation":"After decryption replaces EncryptedAssertions with plain Assertions, the template re-marshals the Response DOM so that decrypted ID attributes are re-established at the DOM level. A MarshallingException during this re-marshall is wrapped in a Saml2Exception.","triggerScenarios":"Calling decrypt(response) when at least one assertion was decrypted and XMLObjectSupport.marshall(response) fails due to malformed/duplicate XML attributes, null required elements, or an inconsistent object/DOM state after decryption.","commonSituations":"IDP-issued XML that violates SAML schema (duplicate IDs); prior manual mutation of the Response XMLObject; OpenSAML version behavior change in marshalling; very large messages hitting DOM configuration limits.","solutions":["Inspect the wrapped MarshallingException for the specific XML element causing the failure and validate the IDP's response against the SAML schema.","Avoid mutating the Response XMLObject between parsing and decrypt(); re-parse the raw XML before decrypting.","Ensure the Response was parsed by OpenSAML's ParserPool so its DOM state is consistent for re-marshalling.","Upgrade spring-security-saml2-service-provider / OpenSAML to a version where the marshalling bug (if any) is fixed."],"exampleFix":"// before\nResponse response = customParse(rawXml);\ntemplate.decrypt(response);\n// after\nResponse response = (Response) XMLObjectProviderRegistrySupport.getParserPool()\n    .parse(new ByteArrayInputStream(rawXml)).getXMLObject();\ntemplate.decrypt(response);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    template.decrypt(response);\n} catch (Saml2Exception ex) {\n    if (ex.getCause() instanceof MarshallingException) {\n        logger.error(\"Post-decryption re-marshall failed; check IDP XML for schema violations\", ex);\n    }\n}","preventionTips":["Always parse responses with OpenSAML's ParserPool so DOM state stays consistent.","Do not mutate the Response XMLObject between parse and decrypt.","Validate IDP-generated XML against the SAML schema in integration tests."],"tags":["saml2","marshalling","xml","decryption","opensaml5"],"backgroundTag":"schema-validation-failed","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}