Security insights

SAML and XML Signature Wrapping: An Old Class That Still Bites

SolarWinds. GitHub Enterprise. GitLab. Every one of these breaches turned on a SAML bug. A practical guide to the attack class that has defeated enterprise SSO for 20 years — written so a founder and an engineer can act on the same article.

BU
BugSwagger Team

In December 2020, Russian SVR operators used a single forged XML document to authenticate as anyone they wanted inside the M365 environments of nine U.S. federal agencies and roughly 100 private-sector companies. They never typed a password. They never solved an MFA prompt. They stole a certificate from an Active Directory Federation Services (ADFS) server, signed their own SAML tokens with it, and walked through the front door.

That attack — now known as Golden SAML — is the single most consequential authentication bypass of the last decade. SolarWinds itself reported spending over $40 million in the first three months on investigation and remediation. Affected companies, per industry analysis, lost an average of 11% of annual revenue in the year that followed. And the technique that made it possible — abusing the way SAML signatures are computed and verified — is a 20-year-old bug class that is still finding fresh victims in 2026.

This guide is written for two readers. If you are a founder or executive selling into enterprise — where SAML SSO is a non-negotiable procurement requirement — the first sections explain what is actually at stake and the five questions to put to your team. If you are an engineer responsible for a SAML integration, the technical sections cover the attack classes, the recent CVEs (including 2024–2026 disclosures), and the defenses that actually hold up.

The 60-second version for non-technical leaders

SAML is the protocol that lets your customers' employees log into your product using their corporate identity (their Okta, Microsoft Entra, Google Workspace, Ping, ADFS, etc.). It is the technology behind the "Sign in with SSO" button that every mid-market and enterprise buyer demands. If you sell B2B above ~50 seats, you support SAML.

The problem: SAML's security model is built on a single fragile assumption — that the XML document carrying the user identity has not been tampered with. The mechanism that proves this (XML Digital Signatures) is a 2002-era specification, written before modern web security existed, and it is breathtakingly easy to misimplement. Two decades of bugs later, the same attack class keeps producing critical findings — including in the most security-conscious organizations on Earth.

The reason this matters at the executive level:

  • The blast radius is the entire customer base. A SAML bug is not a "single user gets phished" event. It is "an attacker logs in as any user at any customer tenant, including admins, without credentials." That is the only kind of bug that makes the front page of TechCrunch.
  • The financial stakes are concentrated in your enterprise tier. IBM's 2024 Cost of a Data Breach Report puts the financial-services average at $6.08 million per breach — 22% above the global mean. Global account-takeover losses hit ~$13B in 2023 and are projected to reach $17B in 2025. 83% of organizations report being hit by at least one ATO attack; 26% are hit weekly.
  • Procurement is now actively asking. Modern enterprise security questionnaires (Vanta, Drata, OneTrust, custom SIG-Lite) now ask specifically about SAML signature validation behavior, key pinning, and metadata trust. A vague answer here will block a six- or seven-figure deal.
  • The bug class is producing fresh CVEs every year. 2024 brought GitHub Enterprise (CVSS 10.0), the libxml2 SAML bypass, and Mender. 2025 brought ruby-saml parser differentials and the samlify 9.9 CVSS bypass. The PortSwigger team disclosed three brand-new attack classes (attribute pollution, namespace confusion, void canonicalization) in late 2025 / early 2026. This is not a solved problem.

Translation: if you ship SAML in production and have not had an outside specialist pressure-test the integration against the modern (2024–2026) attack catalog, your authentication has a real chance of being defeated by a technique from 2005 — wearing a 2026 paint job.

What SAML actually does

SAML (Security Assertion Markup Language) is a SOAP-era protocol that lets an identity provider (IdP — Okta, Entra, ADFS, Google) assert facts about a user to a service provider (SP — your application). The IdP signs an XML document containing the user's identity and attributes; the SP verifies the signature; the SP trusts the user identity in the document.

The signature is the entire security model. If an attacker can forge a valid-looking signature, or get the SP to verify the signature on one part of the document while reading user identity from a different part, the attacker becomes whoever they say they are.

This is the structural weakness that all of the attacks below exploit. The XML signature standard does not require the verifier and the consumer to agree on what part of the document is "the signed part." When they disagree, the attacker wins.

Attack 1 — Classic XML Signature Wrapping (XSW)

What an attacker does, in plain English: takes a valid SAML response captured from their own legitimate login, then restructures the XML so that the original signed identity ("alice") is hidden where the verifier still finds it, while a new, unsigned identity ("admin") is placed where your application reads from. The signature passes. The wrong user logs in.

Business impact: total authentication bypass as any user the attacker chooses. The attack works from a single legitimate account — meaning anyone who can sign up for your free tier can potentially log in as your largest customer's admin.

Technical mechanics. The classic XSW attack restructures the SAML response so the signed <Assertion> is preserved (and verifies), while a duplicate unsigned <Assertion> with attacker-chosen identity is placed where the application's XPath query lands first:

<samlp:Response>
  <!-- Attacker-controlled assertion, NOT signed, read by the app -->
  <saml:Assertion ID="evil">
    <saml:Subject><saml:NameID>admin@victim.com</saml:NameID></saml:Subject>
    <saml:AttributeStatement>...</saml:AttributeStatement>
  </saml:Assertion>

  <!-- Original signed assertion, untouched, found by the verifier -->
  <saml:Assertion ID="orig">
    <ds:Signature>...</ds:Signature>
    <saml:Subject><saml:NameID>attacker@example.com</saml:NameID></saml:Subject>
  </saml:Assertion>
</samlp:Response>

There are at least eight named XSW variants in the academic literature — wrapping the assertion, duplicating the assertion, hiding the assertion in <Object> elements, hiding it in metadata, hiding it under the signature itself. Each one exploits a subtly different gap between "what gets verified" and "what gets used."

The first XSW papers were published in 2005. We still find production SAML deployments vulnerable to them in 2026.

Recent named CVE: CVE-2025-47949 in samlify (Node.js SAML library, >200k weekly downloads) — CVSS 9.9. Fixed in 2.10.0. The bug: lax XML parsing rules meant the SP processed an attacker-injected unsigned identity alongside the original signature.

Attack 2 — Parser differentials (the modern resurgence)

What an attacker does, in plain English: exploits the fact that the SAML library uses one XML parser to verify the signature, and a different XML parser to extract the user identity. The two parsers disagree about what the document actually says. The attacker chooses what each parser sees.

Business impact: the same as XSW — full authentication bypass as any user. But this class is more dangerous because it bypasses fixes designed for classic XSW. Teams that patched XSW years ago are still vulnerable.

Technical mechanics. Many SAML libraries use two XML parsers internally — one to canonicalize and verify the signature (often the faster, stricter Nokogiri or libxml2), and one to extract the assertion's identity attributes (often the more permissive REXML or in-language parser). Differences in how these parsers handle namespaces, duplicate IDs, or malformed elements let an attacker craft a document where:

  • Parser A sees a legitimate signed assertion ("alice")
  • Parser B sees a completely different unsigned assertion ("admin")
  • Both parsers consider their input valid
  • Verification passes against A; identity comes from B

Real CVEs from this class:

  • CVE-2024-45409, CVE-2025-25291, CVE-2025-25292 — ruby-saml < 1.18.0. Disclosed by GitHub Security on March 12, 2025. The bug: ruby-saml's SignedInfo element is canonicalized and verified via Nokogiri, but the DigestValue is read via REXML — severing the cryptographic connection between the hashed content and the signature. Affected projects: omniauth-saml, GitLab (exploitation confirmed against GitLab EE).
  • CVE-2024-4985 and CVE-2024-9487 — GitHub Enterprise Server. CVSS 10.0 (maximum). Stems from quirks in libxml2 used for SAML validation. A threat actor could forge a SAML response and gain administrator privileges, providing unrestricted access to all instance contents without any authentication.
  • CVE-2024-37019 — Mender. Account takeover via SAML in multi-tenant setups; compromises tenant separation, RBAC, and the entire SSO trust boundary.

Attack 3 — Void canonicalization (new, 2025–2026)

What an attacker does, in plain English: tricks the SAML library into computing a signature over an empty string, then crafts a separate SAML document that, when signed, also yields an empty string — making the signatures interchangeable.

Business impact: full bypass, against libraries that explicitly patched the older bug classes. This is a 2025-discovered attack and most teams have not yet considered it.

Technical mechanics. XML signatures are computed over the canonicalized form of a document — a normalized byte sequence. The canonicalization spec handles "relative URI references" by attempting to resolve them. If the resolution fails (which is implementation-specific), most libraries silently treat the canonicalized output as an empty string. An attacker can therefore:

  1. Get the library to produce "" as the input to the hash function.
  2. Reuse the resulting signature against any other document whose canonicalization also fails to "".
  3. Effectively forge signatures with no cryptographic material at all.

Disclosure timeline: Reported by researcher Zakhar Fedotkin to multiple vendors on August 27, 2025. Ruby-SAML published CVE-2025-66568 and CVE-2025-66567 on December 8, 2025. Affected products include ruby-saml (all versions before 1.18.0, including the supposedly patched 1.12.4), PHP-SAML libraries, and Rob Richards' xmlseclibs. On January 20, 2026, Okta publicly declined to modify its signing behavior, citing SAML standard compliance. CSO Online's coverage was titled "SAML authentication broken almost beyond repair."

Attack 4 — Attribute pollution and namespace confusion

What an attacker does, in plain English: sends a SAML document with two copies of the same attribute, one using a sneaky XML namespace trick that some parsers respect and others ignore. The signature verifier sees one value; your code reads the other.

Business impact: bypass of signature validation for specific identity fields (NameID, role attributes, group memberships). The attacker controls who they become without forging the whole assertion.

Technical mechanics. XML namespaces create a second layer of identity for elements and attributes. An email attribute in namespace X is technically different from an email attribute in namespace Y — but human-written extraction code rarely distinguishes them. An attacker who can inject duplicate attributes with manipulated namespace prefixes can make the signature verifier read value A while your application reads value B.

These were disclosed alongside void canonicalization in late 2025. They affect the same ecosystem (Ruby-SAML, PHP-SAML, xmlseclibs).

Attack 5 — Golden SAML (post-compromise persistence)

What an attacker does, in plain English: compromises your IdP server (ADFS, Entra Connect, Okta hybrid) and extracts the private key used to sign SAML assertions. From that moment, the attacker can forge a valid SAML response for any user, any application, any permission level — and the forged response is cryptographically indistinguishable from a legitimate one.

Business impact: the worst category of breach because it persists across password resets, MFA enrollments, and even key rotations (until you rotate and redistribute the new public key to every SP — a multi-week operation in most enterprises). This is the technique used in SolarWinds.

Technical mechanics.

1. Compromise the IdP server (Active Directory FS, Entra Connect, etc.).
2. Extract the token-signing certificate's private key.
   - On ADFS: dump the DKM (Distributed Key Manager) from Active Directory,
     decrypt the certificate, recover the RSA private key.
3. Use the private key to sign arbitrary SAML assertions:
   - Any NameID
   - Any group membership
   - Any session duration (years if you want)
4. Submit the forged assertion to any SAML SP in the federation.
   The SP trusts the IdP's public key, the signature verifies, the user
   is authenticated as whoever the assertion says they are.
5. No login event, no MFA prompt, no password use. The IdP's logs
   never see the authentication because it never happened there.

Public history: The Golden SAML technique was first described by CyberArk in 2017. It was used at industrial scale in the SolarWinds compromise (2020). CISA's remediation guidance explicitly calls out "Golden SAML" as the technique that allowed lateral movement to M365. Microsoft was reported by ProPublica in 2024 to have refused to fix the underlying ADFS weakness years before SolarWinds, citing customer-impact concerns.

Attack 6 — Metadata trust on first use

What an attacker does, in plain English: at the moment your IT admin sets up a new SAML integration, the attacker (controlling the network — corporate Wi-Fi, hotel, conference) swaps the IdP's public key for their own. The misconfiguration persists across key rotations because it lives in your SP's static config.

Business impact: permanent ability to forge tokens against the affected SP without ever compromising the IdP.

Technical mechanics. SAML's metadata exchange — how SPs learn which keys to trust from their IdPs — is often the weakest link in the chain. If the metadata is served over an unsigned channel (HTTP instead of HTTPS, or HTTPS with a misconfigured chain), an attacker who controls the network can swap keys at the moment of trust establishment.

Many enterprise SAML setups fetch metadata once at configuration time. If that configuration happens on a coffee-shop Wi-Fi during onboarding, the trust anchor is whatever the attacker handed to the admin. The damage persists across rotations because the SP has no way to detect that its trusted key was wrong from day one.

What "secure SAML" actually looks like

The defenses below close most of the attack classes above. Each one is a configuration decision or a single guard in code.

  1. Use one XML parser end-to-end. The same parser must canonicalize, verify the signature, and extract identity attributes. Parser differentials are eliminated structurally — not by patching individual variants.
  2. Pin the IdP's signing certificate. Hard-code (or store in your secure config) the exact certificate fingerprint expected from each IdP. Refuse anything else. Reject the "trust whatever metadata says" mode.
  3. Reject documents with multiple <Assertion> elements. A legitimate SAML response has exactly one. Anything else is an XSW attempt.
  4. Validate the signature reference. The signature should explicitly reference the assertion (or response) ID. Check that the ID being signed is the ID being consumed. Reject if they differ.
  5. Enforce signature on the entire <Response> or <Assertion>. Not just one sub-element. The defense against "wrap a new assertion outside the signed scope" is to refuse documents where the signed scope does not match the consumed scope.
  6. Reject empty or null canonicalization output. Explicitly check that the canonicalized input to the hash function is non-empty. This closes void canonicalization.
  7. Validate InResponseTo, NotBefore, NotOnOrAfter, and Audience. Each of these is a separate findable bug class when missed.
  8. Use a maintained library. Roll-your-own SAML is the single most reliable source of findings in this category. If you have not budgeted the engineering time to chase CVEs in your chosen library — pick a different library, or use a managed SSO gateway.

The boardroom translation table

What your team says What it means What it could cost you
"We use ruby-saml / samlify / xmlseclibs" You depend on a library with multiple critical CVEs in the last 18 months. Patch cadence matters. Any unpatched window = full ATO. Average ATO breach: $5M.
"We trust the IdP metadata URL" Whoever controlled the network during onboarding may have substituted keys. We may never know. Permanent token forgery against this customer until manual cert pinning.
"We support multiple SAML parsers / both XML libraries" Parser differential is on the menu. ruby-saml / GitHub Enterprise scenario. CVSS 10.0 territory. Procurement deal-breaker.
"We rolled our own SAML" You are competing with 20 years of accumulated attack research, alone. Almost certain finding in any external assessment.
"Our SAML keys haven't rotated in years" If the key were ever exposed (e.g., backup leak, ex-employee), there is no remediation in progress. Golden SAML scenario. Indistinguishable from legitimate auth in logs.

Five questions a non-technical leader should ask the engineering team

  1. "Which SAML library do we use, and when did we last update it?" If the answer involves ruby-saml < 1.18.0, samlify < 2.10.0, or any version of xmlseclibs you cannot pin to a 2025 release — that is a finding before the pentest starts.
  2. "Do we use the same XML parser for signature verification and attribute extraction?" The right answer is yes. If the answer involves "well, there's a fast path and a slow path," you have a parser differential risk.
  3. "Do we pin the IdP signing certificate, or do we trust whatever the metadata URL returns?" Pinning is the right answer. Auto-trust is convenient and dangerous.
  4. "What happens if a SAML response contains two assertions? Or an assertion with two NameIDs?" The right answer is "we reject it." Anything else is an XSW invitation.
  5. "How will we detect a Golden SAML attack? What would the signal look like?" Most teams have no answer. The truthful one is: "we won't, unless we correlate IdP auth events with SP auth events and look for SP authentications without matching IdP events."

What we recommend on greenfield integrations

If you have a choice — and on new integrations, increasingly you do — we recommend OIDC over SAML. OIDC has a smaller attack surface, stronger default behavior in modern libraries, and an order of magnitude fewer historical bug classes. The enterprise tooling has caught up; you no longer have to ship SAML for compatibility with most identity providers.

If you must support SAML — and at enterprise scale, you usually must — use a battle-tested library, enable strict mode, pin certificates, run a single parser end-to-end, and budget for a dedicated SSO pressure test before going live. SAML is not a "configure and forget" technology. It is a configuration the attack community keeps actively breaking, and your defenses must be actively maintained at the same cadence.

What we test, every SAML engagement

  • All eight classic XSW variants (assertion wrap, response wrap, signature wrap, etc.).
  • Parser differential attacks: dual-parser exploitation with crafted namespace and ID collisions.
  • Void canonicalization: relative URI resolution failures, empty-string signature reuse.
  • Attribute pollution and namespace confusion: duplicate attributes with crafted prefixes.
  • Signature reference manipulation: signing one element, consuming another.
  • Metadata substitution: MITM at trust-establishment time, key rollover abuse.
  • InResponseTo bypass: replay attacks and request/response binding failures.
  • Audience restriction bypass: SAML responses accepted by the wrong SP.
  • Time-window abuse: pre-issued assertions, clock skew exploitation.
  • Encryption downgrade: forcing EncryptedAssertion to plaintext.

If your last assessment did not specifically test for the 2025–2026 attack classes (parser differentials, void canonicalization), your SAML integration has not been pressure-tested against the current attacker. Most of the bugs found in the last 18 months would have passed unnoticed under a 2022-era checklist.

The bottom line

SAML is the enterprise SSO standard. It will be for years. It will keep producing critical bugs because the underlying spec is too flexible, the libraries are too lenient, the parsers disagree with each other, and the SPs trust the signature too much.

The good news: the defenses are known, the tooling exists, and the cost of getting them right is small relative to the cost of getting them wrong. A SolarWinds-shaped event is the most expensive single line item your company will ever absorb. A focused SAML pressure-test, run against the modern attack catalog before the enterprise procurement team starts auditing you, is not.

If you ship SAML in production without ever having had an outside expert pressure-test it, your authentication has a real chance of being defeated by a technique from 2005 — and a meaningful chance of being defeated by one from 2026.

Found this helpful?

Want a hand-tested assessment for your own stack?

Tell us what you're protecting — we'll respond within one business day with a scoped proposal written by a pentester.