SAML Replay Flaw: Signed Assertion, Unsigned Response Envelope
SAML's InResponseTo field is unsigned and strippable, letting attackers bypass replay protection; the fix is binding checks to the signed assertion ID.
Most SAML identity providers sign the <Assertion> element but leave the outer <Response> envelope unsigned. Replay protection, however, is typically keyed off InResponseTo — an attribute that lives on the unsigned Response, not the signed Assertion. Strip that attribute from a captured, legitimate response and the signature still validates perfectly, because it never covered the envelope in the first place.
The attack requires no cryptography: capture a real SAML response, delete InResponseTo, and replay it. The service provider, seeing no InResponseTo, treats it as an unsolicited IdP-initiated login and skips the replay check entirely — while signature, issuer, and timestamp checks all pass, since none of them were designed to catch this specific bypass. The assertion becomes a reusable skeleton key.
The fix isn't more validation, it's validating the right field: bind replay protection to the assertion's own ID, which is signed and always present, using a one-time-use cache bounded by each assertion's NotOnOrAfter. InResponseTo matching and rejection of unsolicited responses should remain as defense in depth, but the load-bearing check has to sit on signed bytes. The broader lesson for engineers: a signature only proves who produced the data, not that it's fresh, targeted, or unused — each of those guarantees must be anchored to a field the signature actually covers.