Skip to content

Instantly share code, notes, and snippets.

@russellhaering
Created March 12, 2026 06:21
Show Gist options
  • Select an option

  • Save russellhaering/f1a824c978b5083ea862a9eac6ecd096 to your computer and use it in GitHub Desktop.

Select an option

Save russellhaering/f1a824c978b5083ea862a9eac6ecd096 to your computer and use it in GitHub Desktop.
Comprehensive SAML Security Vulnerability Research Report — 9 attack classes, 60+ CVEs

Comprehensive SAML Security Vulnerability Research Report

Researched: GitHub Advisory Database, NVD, CERT/CC, Mattermost Security Blog, project-specific advisories.


ATTACK CLASS 1: XML Signature Wrapping (XSW)

Overview

XSW attacks exploit the disconnect between signature verification and data extraction in SAML processors. The attacker moves or copies the signed content to a different location in the XML document, then inserts malicious content where the SP will read it. The signature remains valid over the original content, but the SP processes the attacker's injected content.

Known CVEs

CVE Library Severity Year
CVE-2024-45409 ruby-saml Critical (10.0) 2024
CVE-2025-47949 samlify (npm) Critical 2025
CVE-2025-46572 passport-wsfed-saml2 (npm) Critical 2025
CVE-2025-54419 @node-saml/node-saml (npm) Critical 2025
CVE-2025-54369 @node-saml/node-saml (npm) Critical 2025
CVE-2016-5697 ruby-saml High 2016
CVE-2016-1000253 onelogin/php-saml Moderate 2016
CVE-2020-5407 Spring Security SAML High 2020
CVE-2024-6800 GitHub Enterprise Server Critical 2024
CVE-2024-6202 HaloITSM Critical 2024
CVE-2023-34923 TOPdesk High 2023
CVE-2020-13415 Aviatrix Controller Moderate 2020

Description

XSW attacks come in multiple variants (XSW1-XSW8), each placing the malicious content in a different part of the XML document tree:

  • XSW1: Attacker adds a new unsigned Assertion before the signed one, keeping the signature intact
  • XSW2: Wraps a new unsigned Response around the signed content
  • XSW3-8: Various combinations of moving the signed Assertion into Extensions, Object, or other elements while the SP reads an unsigned copy

How it was exploited (CVE-2024-45409 - ruby-saml)

Ruby-SAML <= 12.2 and 1.13.0 <= 1.16.0 did not properly verify the signature of the SAML Response. An unauthenticated attacker with access to any signed SAML document could forge a SAML Response/Assertion with arbitrary contents, logging in as any user.

Mitigation

  • Ensure the signature references the correct element: The signature's Reference URI must point to the exact element being processed
  • Validate that signed content is what's being read: After signature verification, ensure the data extracted for authentication decisions comes from the verified (signed) subtree
  • Reject documents with multiple Assertions (unless all are individually verified)
  • Use strict XPath for extracting signed elements: Don't just search for the first Assertion element; verify it's the one referenced by the signature

Relevance to Go SAML SP

HIGH. Go SAML libraries have been specifically vulnerable (see gosaml2 CVE-2020-29509). The implementation must:

  1. Verify the signature covers the exact Assertion being processed
  2. Reject responses with multiple Assertions unless individually signed
  3. Validate Reference URI matches the Assertion's ID attribute
  4. Not trust any assertion data that wasn't within the signed subtree

ATTACK CLASS 2: Go encoding/xml Round-Trip Vulnerabilities (Parser Differentials)

Overview

This is the most critical class of vulnerabilities specific to Go SAML implementations. Go's encoding/xml package does not preserve XML semantics during tokenization round-trips. Maliciously crafted XML mutates when parsed and re-serialized, meaning the signature verification stage sees different content than the data extraction stage.

Known CVEs

CVE Component Severity Year
CVE-2020-29509 Go encoding/xml (attributes) Critical (9.8) 2020
CVE-2020-29510 Go encoding/xml (directives) Critical (9.8) 2020
CVE-2020-29511 Go encoding/xml (elements) Critical (9.8) 2020
CVE-2020-27846 crewjam/saml Critical (9.8) 2020
CVE-2020-26290 dex (SAML connector) Critical 2020
CVE-2020-26276 fleetdm/fleet High 2020

Affected Go Libraries

  • github.com/russellhaering/gosaml2 - Fixed in v0.6.0
  • github.com/crewjam/saml - Fixed in v0.4.3
  • github.com/dexidp/dex - Fixed in v2.27.0
  • github.com/fleetdm/fleet - Fixed
  • 20+ commercial products contacted during coordinated disclosure by Mattermost

Technical Details (from Mattermost coordinated disclosure, Dec 2020)

Three independently exploitable vulnerabilities in Go's encoding/xml:

  1. Attribute instability (CVE-2020-29509): Namespace prefixes on XML attributes are not correctly preserved during tokenization round-trips. The observed namespace and local name of attributes can change between parse cycles.

  2. Directive instability (CVE-2020-29510): XML directives (DTD, processing instructions) mutate during round-trips.

  3. Element instability (CVE-2020-29511): Element names/namespaces can change during round-trips.

Impact on SAML: An attacker can craft a signed SAML response that appears correctly signed during verification, but when the SP re-parses the XML to extract claims, the mutation causes different elements to be read. This enables:

  • Full authentication bypass: Attacker impersonates any user
  • Arbitrary privilege escalation: Within the scope of the SAML SP

Mitigation

  • Use github.com/mattermost/xml-roundtrip-validator to validate XML documents before processing
  • Avoid re-serializing/re-parsing XML between signature verification and data extraction
  • The Go team has NOT fully fixed the underlying encoding/xml issues (as of the disclosure)
  • Go 1.16+ added API to disable namespace prefix parsing but this doesn't fully resolve the issue

Relevance to Go SAML SP

CRITICAL. This is THE fundamental vulnerability class for Go SAML implementations. Any Go SAML SP that uses encoding/xml for both signature verification and data extraction is potentially vulnerable. The gosaml2 library specifically had to integrate the Mattermost xml-roundtrip-validator as a mitigation.


ATTACK CLASS 3: XML Comment Injection / Canonicalization Attacks

Overview

The famous 2018 vulnerability (Duo Labs / CERT VU#475445) discovered that multiple SAML libraries incorrectly handle XML comments within text nodes during canonicalization. When an XML comment is placed inside a text node (e.g., user@evil.com<!-- -->admin), some libraries strip the comment and concatenate the text, while others only read text before or after the comment.

Known CVEs

CVE Library Severity Year
CVE-2017-11427 OneLogin python-saml High 2018
CVE-2017-11428 OneLogin ruby-saml High 2018
CVE-2017-11429 Clever saml2-js Moderate 2018
CVE-2017-11430 OmniAuth-SAML High 2018
CVE-2018-0489 Shibboleth openSAML C++ High 2018
CVE-2018-5387 Wizkunde SAMLBase High 2018
CVE-2018-7340 Duo Network Gateway High 2018
CVE-2025-66568 ruby-saml (Libxml2 C14N) Critical 2025
CVE-2025-66567 ruby-saml (namespace handling) Critical 2025

CERT Advisory VU#475445 (Feb 2018)

Discovered by: Kelby Ludwig of Duo Security (Duo Labs)

Affected vendors confirmed: Clever Inc., Duo Security, OmniAuth, OneLogin Inc., Pulse Secure, Shibboleth Consortium, Wizkunde B.V. Not affected: AssureBridge, Box, CA Technologies (+ 16 more vendors evaluated)

Technical Details

  1. XML DOM traversal APIs inconsistently handle comments within text nodes
  2. Some APIs return only pre-comment text when getting innerText
  3. Signature verification uses canonicalization (which preserves all text), but the application reads truncated text
  4. Example: NameID admin@evil.com<!--INJECTED-->.legit.com might be signed as-is, but the SP reads only admin@evil.com

Recent Recurrence (2025)

CVE-2025-66568 and CVE-2025-66567 show this class of vulnerability continues to recur:

  • CVE-2025-66568: ruby-saml vulnerable via Libxml2 canonicalization error that bypasses Digest/Signature validation
  • CVE-2025-66567: ruby-saml SAML authentication bypass due to namespace handling (parser differential)

Mitigation

  • Never use different parsers/APIs for verification vs. data extraction
  • Reject XML with comments in security-critical text nodes
  • Use the same canonicalized form for both signature check and value extraction
  • Validate that text node content matches expected patterns (no embedded comments)

Relevance to Go SAML SP

HIGH. Go's encoding/xml strips comments during parsing, so the signed canonicalized form (which may include comments) could differ from what Go reads. This overlaps with Attack Class 2. Mitigation: ensure the XML is validated with the roundtrip validator before processing.


ATTACK CLASS 4: Multiple Assertion / Assertion Injection Attacks

Overview

An attacker injects additional unsigned Assertion elements into a signed SAML Response. If the SP doesn't properly verify which Assertion was signed, it may process the attacker's unsigned Assertion.

Known CVEs

CVE Library Severity Year
CVE-2022-41912 crewjam/saml (Go) Critical (9.8) 2022
CVE-2025-54369 @node-saml/node-saml Critical 2025
CVE-2021-23365 tyk-identity-broker (Go) Critical 2021

Technical Details (CVE-2022-41912)

The crewjam/saml Go library prior to version 0.4.9 was vulnerable to authentication bypass when processing SAML responses containing multiple Assertion elements. The library verified the signature of one Assertion but read claims from a different one.

Mitigation

  • Reject SAML responses containing multiple Assertion elements (unless each is individually verified)
  • Ensure the Assertion being processed is the same one whose signature was verified
  • Use the Assertion's ID attribute to correlate signature Reference with processed content

Relevance to Go SAML SP

CRITICAL. Both major Go SAML libraries (crewjam/saml and gosaml2) have had variants of this vulnerability. The SP must:

  1. Count Assertion elements and reject if more than expected
  2. Verify each Assertion's signature individually
  3. Correlate signed content with processed content by ID

Note: gosaml2 issue #219 (open as of 2025) reports that "Assertions signature is not verified when the response is signed" - a behavioral regression that could enable this attack class.


ATTACK CLASS 5: Signature Validation Bypass

Overview

Various techniques to bypass XML digital signature validation in SAML, including:

  • Removing the signature entirely and hoping the SP doesn't require it
  • Modifying signed content and re-signing with attacker-controlled key
  • Exploiting C14N (canonicalization) algorithm differences
  • Using embedded public keys (KeyValue) instead of trusted certificates

Known CVEs

CVE Library Severity Year
CVE-2020-15216 gosaml2/goxmldsig Critical 2020
CVE-2023-48703 RobotsAndPencils/go-saml High (7.5) 2023
CVE-2020-36563 RobotsAndPencils/go-saml Moderate 2020
CVE-2025-66475 onelogin/php-saml (xmlseclibs) Critical 2025
CVE-2020-5390 PySAML2 High 2020
CVE-2021-21238 PySAML2 Moderate 2021

gosaml2-Specific: CVE-2020-15216 (Signature Validation Bypass)

Affected versions < v0.5.0. Given a valid SAML Response, an attacker could modify the document, bypassing signature validation to pass off the altered document as signed. This enabled users accessing accounts other than the one authenticated, or full authentication bypass with an expired signed SAML Response.

go-saml: CVE-2023-48703 (Authentication Bypass via xmlsec1)

RobotsAndPencils/go-saml calls xmlsec1 without --enabled-key-data restriction, allowing an attacker to sign SAML assertions themselves and embed the public key directly in the token. The library is archived with no fix planned - users must migrate.

go-saml: CVE-2020-36563 (SHA-1 Signatures)

RobotsAndPencils/go-saml uses SHA-1 for XML digital signatures, which is cryptographically weak and allows potential signature forgery.

Mitigation

  • Always require signatures (never accept unsigned responses/assertions)
  • Only accept signatures from trusted certificates (not embedded KeyValue)
  • Use strong hash algorithms (SHA-256 or better, never SHA-1)
  • Validate the certificate chain against known IdP certificates
  • Validate the C14N algorithm used matches expected values

Relevance to Go SAML SP

CRITICAL. gosaml2 itself has had this exact vulnerability. The SP must:

  1. Always require and verify signatures
  2. Only trust pre-configured IdP certificates
  3. Use SHA-256+ for digest/signature algorithms
  4. Validate the entire signature chain properly

ATTACK CLASS 6: Assertion Replay Attacks

Overview

An attacker captures a valid, signed SAML assertion and replays it to gain unauthorized access. This works when the SP doesn't track which assertions have already been consumed.

Known CVEs

CVE Library/Product Severity Year
CVE-2025-64131 Jenkins SAML Plugin High 2025
CVE-2024-5249 Akana API Platform Moderate 2024
CVE-2021-41030 FortiClient EMS Critical 2021
CVE-2022-44457 Mendix SAML Module Critical 2022
CVE-2022-37011 Mendix SAML Module Critical 2022
CVE-2018-14637 Keycloak High 2018
CVE-2017-1000452 samlify (npm) High 2017

Technical Details

SAML assertions include temporal validity conditions (NotBefore, NotOnOrAfter) and may include a unique InResponseTo identifier. Replay attacks succeed when:

  1. The SP doesn't maintain a replay cache of consumed assertion IDs
  2. The SP doesn't validate NotOnOrAfter / NotBefore temporal conditions
  3. The SP doesn't validate InResponseTo correlation with pending requests

Jenkins SAML Plugin (CVE-2025-64131)

The Jenkins SAML Plugin did not implement a replay cache, allowing captured SAML assertions to be reused.

Mitigation

  • Maintain a replay cache: Store consumed Assertion IDs and reject duplicates
  • Validate temporal conditions: Check NotBefore and NotOnOrAfter with appropriate clock skew tolerance
  • Validate InResponseTo: Correlate responses with pending authentication requests
  • Validate Destination: Ensure the response is intended for this SP's ACS URL
  • Use short validity windows: Minimize the replay window

Relevance to Go SAML SP

HIGH. gosaml2 does validate temporal conditions (NotBefore/NotOnOrAfter), but:

  1. Replay cache must be implemented by the application (not built into gosaml2)
  2. InResponseTo validation must be implemented by the application
  3. Clock skew tolerance must be reasonable (not too large)

ATTACK CLASS 7: Denial of Service

Overview

DoS attacks against SAML implementations, including decompression bombs, XML entity expansion (Billion Laughs), and resource exhaustion.

Known CVEs

CVE Library Severity Year
CVE-2023-26483 gosaml2 Moderate (5.3) 2023
CVE-2020-7731 gosaml2/goxmldsig High (7.5) 2020
CVE-2025-54572 ruby-saml Moderate 2025
CVE-2025-46784 Lasso (Entrouvert) Critical 2025
CVE-2025-46705 Lasso (Entrouvert) Critical 2025
CVE-2025-46404 Lasso (Entrouvert) Critical 2025

gosaml2: CVE-2023-26483 (Deflate Decompression Bomb)

SAML SPs using gosaml2 were susceptible to DoS via a crafted deflate-compressed request that consumes significantly more memory than the original request size. Maximum deflate compression ratio is 1032:1. Fixed in v0.9.0.

gosaml2: CVE-2020-7731 (Nil-Pointer Dereference)

In versions prior to v0.7.0, an attacker could supply an invalid assertion triggering a panic from nil-pointer dereference. Fixed in v0.7.0.

Mitigation

  • Limit decompressed size: Set maximum size for deflate-decoded SAML messages
  • Disable DTD processing: Prevent XML entity expansion attacks
  • Handle panics: Use recover() for nil-pointer dereferences
  • Rate limit: Throttle SAML endpoint requests
  • Set timeouts: Limit XML parsing time

Relevance to Go SAML SP

MODERATE-HIGH. gosaml2 has had both of these vulnerabilities. Ensure:

  1. Using gosaml2 v0.9.0+ (decompression bomb fix)
  2. Using gosaml2 v0.7.0+ (nil-pointer fix)
  3. Application-level rate limiting on SAML endpoints
  4. Memory limits and timeouts

ATTACK CLASS 8: SAML Authentication Bypass via Namespace Handling / Parser Differentials

Overview

A modern evolution of Attack Classes 2 and 3. Different XML parsers (or different stages of the same parser) interpret XML namespaces differently, allowing attackers to craft documents where the signature covers one interpretation while the SP processes another.

Known CVEs

CVE Library Severity Year
CVE-2025-66567 ruby-saml Critical 2025
CVE-2025-66568 ruby-saml Critical 2025
CVE-2025-25291 ruby-saml Critical 2025
CVE-2025-25292 ruby-saml Critical 2025
CVE-2026-3047 Keycloak SAML High 2026

Technical Details

  • Parser differential: Two different XML parsers (e.g., REXML and Nokogiri in ruby-saml) interpret the same XML differently
  • Namespace confusion: Prefixed namespaces can cause elements to be interpreted as being in different namespaces during different parsing stages
  • C14N differences: Different canonicalization implementations produce different canonical forms

Relevance to Go SAML SP

HIGH. Go's encoding/xml has known namespace handling issues (CVE-2020-29509/29510/29511). Any Go SAML implementation using encoding/xml for parsing must validate XML roundtrip stability. Using etree or other XML libraries for parsing while using encoding/xml for deserialization creates a parser differential risk.


ATTACK CLASS 9: Open Redirect and Session Fixation

Known CVEs

CVE Library/Product Severity Year
CVE-2026-27982 django-allauth Moderate 2026
CVE-2026-22032 Directus SAML Moderate 2026
CVE-2020-12283 Sourcegraph Moderate 2020
CVE-2025-0126 GlobalProtect High 2025
CVE-2019-11881 Rancher Moderate 2019
CVE-2026-29191 ZITADEL Critical (XSS in SAML-post) 2026

Mitigation

  • Validate RelayState URLs against a whitelist of allowed destinations
  • Don't include user-controlled data in SAML POST forms without sanitization
  • Validate Destination attribute in SAML responses
  • Implement CSRF protection on SAML endpoints

COMPLETE gosaml2 VULNERABILITY HISTORY

Advisory CVE Severity Fixed In Description
GHSA-5684-g483-2249 CVE-2020-15216 Critical v0.5.0 Signature Validation Bypass - attacker can modify signed document
GHSA-xhqq-x44f-9fgg CVE-2020-29509 Critical v0.6.0 Authentication Bypass - Go encoding/xml round-trip mutations
GHSA-prjq-f4q3-fvfr CVE-2020-7731 High v0.7.0 Nil-pointer dereference DoS via invalid assertion
GHSA-6gc3-crp7-25w5 CVE-2023-26483 Moderate v0.9.0 DoS via deflate decompression bomb
Issue #219 N/A Potential High OPEN Assertion signature not verified when Response is signed

COMPLETE crewjam/saml VULNERABILITY HISTORY

CVE Severity Fixed In Description
CVE-2020-27846 Critical (9.8) v0.4.3 Signature verification bypass via Go encoding/xml
CVE-2022-41912 Critical (9.8) v0.4.9 Auth bypass via multiple Assertion elements

COMPLETE go-saml (RobotsAndPencils) VULNERABILITY HISTORY

CVE Severity Fixed In Description
CVE-2023-48703 High (7.5) NONE (archived) Auth bypass - xmlsec1 trusts embedded keys
CVE-2020-36563 Moderate NONE (archived) SHA-1 signatures (cryptographically weak)

Note: RobotsAndPencils/go-saml is archived and unmaintained. Migration away is required.


KEY RECOMMENDATIONS FOR A GO SAML SP IMPLEMENTATION

Must-Have Security Controls

  1. XML Roundtrip Validation: Use github.com/mattermost/xml-roundtrip-validator to reject XML documents that mutate during encoding/xml round-trips

  2. Strict Signature Verification:

    • Always require signatures on Responses AND/OR Assertions (configurable)
    • Verify the signature covers exactly the element being processed
    • Validate Reference URI matches the Assertion/Response ID
    • Only trust pre-configured IdP certificates (never embedded KeyValue)
    • Use SHA-256+ for digest and signature algorithms
  3. Anti-XSW Protections:

    • Reject documents with multiple Assertions (unless each is individually verified)
    • Ensure the signed Assertion is the one being processed (ID correlation)
    • Validate the signed element is in the expected position in the document tree
  4. Temporal Validation:

    • Validate NotBefore and NotOnOrAfter conditions
    • Use reasonable clock skew tolerance (e.g., 30-90 seconds)
    • Validate Conditions element fully
  5. Replay Prevention:

    • Maintain a replay cache of consumed Assertion IDs / Response IDs
    • Validate InResponseTo against pending authentication requests (for SP-initiated flows)
  6. Input Validation:

    • Limit decompressed message size (deflate bomb protection)
    • Validate Destination attribute matches the SP's ACS URL
    • Validate Audience restriction matches the SP's Entity ID
    • Reject unexpected XML structures (DTDs, entity declarations)
  7. Robust Error Handling:

    • Handle nil pointers and panics gracefully
    • Never return detailed error messages to clients
    • Log security-relevant events

Architecture Recommendations

  • Single-parse architecture: Parse XML once and use the same parsed representation for both signature verification and data extraction
  • Avoid re-serialization: Never round-trip XML through encoder/decoder between verification and extraction
  • Use etree consistently: If using etree for XML manipulation, use it for all operations
  • Defense in depth: Layer multiple validation checks; don't rely on a single check

SOURCES

  1. GitHub Advisory Database: https://github.com/advisories?query=saml
  2. NVD: https://nvd.nist.gov/vuln/search
  3. CERT/CC VU#475445: https://www.kb.cert.org/vuls/id/475445
  4. Mattermost Go XML Disclosure: https://mattermost.com/blog/coordinated-disclosure-go-xml-vulnerabilities/
  5. Mattermost XML Roundtrip Validator: https://github.com/mattermost/xml-roundtrip-validator
  6. gosaml2 Security Advisories: https://github.com/russellhaering/gosaml2/security/advisories
  7. crewjam/saml Security Advisories: https://github.com/crewjam/saml/security/advisories
  8. gosaml2 Issue #219 (open): russellhaering/gosaml2#219
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment