Safeguard
Vulnerability Analysis

XML signature wrapping attacks explained

XML signature wrapping lets attackers forge signed SOAP and SAML messages without breaking the signature. Here's how the attack works and how to stop it.

James
Principal Security Architect
7 min read

An XML signature wrapping (XSW) attack lets an adversary take a legitimately signed XML message — a SOAP request, a SAML assertion, a WS-Security token — and restructure the document around that signature so the application processes attacker-controlled content while the signature verification still passes. The trick exploits a gap between two separate operations: the cryptographic library checks that a signed element's hash matches its <Reference>, while the application's business logic reads a different element by tag name or position, one the attacker inserted or moved. Both checks technically succeed. First formally described by McIntosh and Austel in a 2005 ACM workshop paper, the attack class was later used to compromise Amazon's EC2 SOAP API in 2011 and 11 of 14 major SAML implementations in 2012. It maps to CWE-347 (Improper Verification of Cryptographic Signature) and remains exploitable today in any service that decouples signature validation from message processing.

What is an XML signature wrapping attack?

An XML signature wrapping attack is a technique for forging the effective content of a digitally signed XML message without breaking its signature. XML Signature (XML-DSig, a W3C Recommendation since 2002) doesn't sign a document as an opaque blob the way a PGP-signed file does — it signs specific elements, referenced by an ID attribute inside a <Reference URI="#id"> pointer, and computes a digest over that element's canonicalized subtree. The verifier's job is narrow: confirm the digest of the element with that ID matches, and confirm the signature over the <SignedInfo> block is valid. Nothing in that check constrains where the signed element sits in the document, or requires the application to read the same element the verifier just checked. An attacker who can intercept or resend a signed message copies the original signed element into a new location — say, inside a forged <soap:Body> — and inserts their own malicious element with the same tag name where the application actually looks. The parser hands the application the attacker's version.

Why does the XML Signature standard allow this to happen?

The XML Signature standard allows this because it was designed to prove that a referenced element hasn't been tampered with, not to prove that element is the one an application should trust and act on. That's a deliberate scoping decision in XML-DSig, not a bug in any single implementation, which is why the vulnerability class resurfaces across unrelated codebases. Most implementations retrieve the signed element by traversing the DOM with an XPath expression like //saml:Assertion or by calling getElementsByTagName() — a lookup that returns the first matching node in document order, or an arbitrary one if duplicates exist — completely separately from the ID-based lookup the crypto library used to compute the digest. If an attacker duplicates a tag, moves the original signed node under a decoy parent (a "wrapper," which gives the attack its name), and puts a forged node where the naive lookup expects to find it, the two code paths — signature verification and business-logic extraction — silently diverge on two different elements.

What real-world incidents have used XML signature wrapping?

Real-world XSW exploitation dates back to at least October 2011, when researchers from Ruhr-University Bochum demonstrated it against Amazon's EC2 SOAP management API and the Eucalyptus cloud platform. In "All Your Clouds Are Belong to Us," Juraj Somorovsky, Mario Heiderich, Jörg Schwenk, and colleagues intercepted a single legitimately signed SOAP request and rewrote it so EC2 executed arbitrary attacker-chosen operations — including launching and terminating instances — under the victim's account, while the message's signature still validated. Both vendors patched the flaw before it saw wide criminal use. The same research group extended the attack in 2012, testing 14 widely deployed SAML single sign-on frameworks and reporting exploitable wrapping flaws in most of them at USENIX Security's "On Breaking SAML: Be Whoever You Want to Be." A later, closely related class of bugs surfaced on February 27, 2018, when Duo Security publicly disclosed vulnerabilities in OneLogin's python-saml (CVE-2017-11427), OneLogin's ruby-saml (CVE-2017-11428), Clever's saml2-js (CVE-2017-11429), OmniAuth-SAML (CVE-2017-11430), Shibboleth's OpenSAML C++ (CVE-2018-0489), and Duo Network Gateway itself (CVE-2018-7340). That batch exploited XML comment injection during canonicalization rather than node relocation — an attacker could truncate a signed NameID with a <!----> comment and have the library silently drop everything after it — but the underlying failure was the same one XSW exploits: the code path that verified the signature and the code path that extracted the identity read different data.

What are the different XSW attack variants?

There are eight documented XSW variants, labeled XSW1 through XSW8, cataloged by researchers extending McIntosh and Austel's original taxonomy. The variants differ in exactly how the signed element and the forged element are arranged relative to each other and to the document root: XSW1 and XSW2 move the original signed element to a sibling position and insert the forged element in its place at the root; XSW3 through XSW5 wrap the signed element inside a copy of its own parent so a naive same-tag-name lookup still matches the forgery first; XSW6 through XSW8 nest the signature itself inside the forged element or move it into an <Extensions>-style block that many parsers skip during business-logic extraction but still traverse during signature verification. The practical point isn't memorizing eight labels — it's that no single structural check (like "reject documents with duplicate IDs") closes every variant, because some of them don't rely on duplicate IDs at all; they rely on the verifier and the application simply looking in different places.

How do you detect and prevent XML signature wrapping attacks?

You prevent XML signature wrapping by making the application process the exact same node the signature verifier checked, not a node found by a separate lookup. The concrete fix: after XML-DSig validation succeeds, retrieve the signed element via the same Reference URI the verifier used — not via a fresh XPath or tag-name query — so there is exactly one code path from "signature valid" to "here is the data." Pair that with strict schema validation against a fixed XSD before any processing, since several XSW variants depend on injecting elements a lenient parser tolerates but a strict schema rejects outright. Reject documents containing duplicate ID attributes or more <Signature> elements than expected, cap the number of Reference elements a single signature is allowed to cover, and canonicalize with Exclusive XML Canonicalization (the mode most WS-Security stacks default to) rather than trusting inclusive canonicalization to preserve namespace context the way an attacker might not expect. The maintainers behind the February 2018 disclosure applied the equivalent fix for their bug class: python-saml, ruby-saml, and the other affected libraries were patched to strip or reject comment nodes before extracting the NameID and to validate that the canonicalized, signed content matched what the application read — closing the specific gap between verification and extraction without requiring any change to the XML-DSig standard itself.

How Safeguard Helps

Safeguard treats XML signature wrapping as a design-level flaw to catch in code and dependencies, not a checkbox to tick once. Safeguard generates SBOMs that flag exactly which SAML, WS-Security, or XML-DSig libraries (OpenSAML, ruby-saml, python-saml, Apache Santuario, and similar) a service depends on, and ingests existing SBOMs to backfill that inventory without a rescan. Reachability analysis then determines whether a flagged library's signature-verification code path is actually invoked on attacker-reachable input — such as an unauthenticated SSO endpoint — cutting noise from CVEs sitting in unused parsing branches. Griffin, Safeguard's AI security agent, reviews the extraction logic around signature checks to flag the specific pattern that enables XSW: verifying one element while reading another. Where a fix is well-defined, such as pinning extraction to the verified Reference URI, Safeguard opens an auto-fix pull request instead of just filing a ticket for someone to triage later.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.