The verifier and the parser disagree.

Research

8 min read

PARSER DIFFERENTIALS

A class of authentication bypass that was named in 2012, mitigated in 2013, and produced new full bypasses in 2025.

The earlier article established that a signature protects a specific sequence of bytes, and that two documents expressing the same information can produce different signatures. This is the operational consequence, and it remains a recurring weakness in deployed signature systems.

The failure has a single shape. One component verifies a signature over some region of the input. Another component reads the input to decide what it means. If those two lookups can be made to resolve differently, the signature is valid and irrelevant at the same time.

The measurement, twice

2012. Somorovsky, Mayer, Schwenk, Kampmann and Jensen analysed fourteen major SAML frameworks at USENIX Security. Eleven were vulnerable to XML Signature Wrapping, including Salesforce, Shibboleth and IBM XS40. Only two frameworks resisted every test case. In three of the fourteen, implementation bugs meant the signature was not checked at all.

The attack is easy to describe. Move the original signed assertion into a wrapper element where it remains present and verifiable. Insert a forged assertion that names a different subject in the position the application reads from. The verifier resolves the reference, finds the original, and confirms the signature. The application queries the document, finds the forgery, and grants the session.

Mitigations were published promptly: schema validation against local hardened schemas, static key selection, ignoring untrusted KeyInfo, and, most importantly, processing only the element the verifier returned.

2025. PortSwigger’s research demonstrated full authentication bypass across the Ruby and PHP SAML ecosystems using attribute pollution, namespace confusion, and a new class of void canonicalization attacks, with a working demonstration against GitLab EE 17.8.4.

Thirteen years, a named attack class, published countermeasures, an OWASP cheat sheet, and the class still produces complete authentication bypasses in widely deployed software.

That recurrence is the finding. It means the problem is not carelessness.

Why it recurs

XML Signature locates what it protects by reference. The signature says the element with this identifier is what I cover, and verification resolves the identifier at verification time, in the attacker’s document.

Any format with that property has this bug latent in it. The signed region is not a position; it is the result of a query, and a sufficiently complex document format permits two queries with the same appearance to return different things.

The pattern generalises immediately beyond XML:

JWT. The alg header field is inside the token and consulted before verification. alg: none was accepted by multiple libraries. Algorithm confusion followed, including presenting HS256 where RS256 was expected and using the public key as the HMAC secret. An unsafely resolved kid can point the verifier at a key of the attacker’s choosing. Duplicate claims create another differential when the verifier reads the first and the application reads the last.

JSON generally. The JSON grammar does not require member names to be unique, and different parsers resolve duplicates differently: some take the first, some the last, some error. Number precision at the boundaries of IEEE 754 creates another differential. Unicode normalization can make two byte sequences render as the same identifier. RFC 8785, the JSON Canonicalization Scheme, exists precisely because signing JSON without a canonical form is not well defined.

ASN.1. DER is canonical; BER is not. A verifier that accepts BER can be handed a second encoding of the same logical value.

Any envelope where an unsigned outer layer wraps a signed inner one, and the application reads fields from the outer layer.

The common element is not a format. It is that something the verifier must trust, such as the algorithm, key identifier or location of the signed data, was taken from the message being verified without being constrained by local policy.

The rules that prevent it

These are design rules rather than fixes, because the fixes have not held.

1. Sign a fixed region, not a referenced one. The signed bytes should be defined by position and length, not located by query. The Dead Simple Signing Envelope takes this approach: the payload type and the payload are each length-prefixed and concatenated into a pre-authentication encoding, which is what gets signed. There is nothing to relocate because nothing is looked up.

2. Verify first, parse once, and use only what the verifier returned. Never re-parse the raw input after verification. The verifier should hand back a parsed object, and that object should be the only source of truth downstream. This single rule eliminates most of the class, and it is violated constantly because it is more convenient to pass the original document along.

3. Never take the algorithm from the message. The verifier’s policy determines which algorithm is acceptable for which key. A field in the message may be compared against that policy; it may never select from it. The same applies to the key identifier: resolve keys from a configured set, not from what the token asks for.

4. Define canonicalization as part of the verification boundary. Some formats require the verifier to reconstruct canonical bytes before checking a signature. When they do, the canonicalization profile must be fixed by the protocol and implemented inside the same trusted boundary as parsing and verification. It must not be selected by the attacker, applied inconsistently, or followed by a second parse of the raw input. The 2025 void canonicalization results show why the canonicalizer itself must be treated as attack surface.

5. Reject rather than repair. Duplicate keys, unexpected elements, ambiguous encodings, trailing bytes: decline. Tolerance is where differentials live, and every accommodation for a slightly malformed input is a place where two implementations can differ.

6. Prefer canonical binary encodings. CBOR with deterministic encoding rules and COSE, or DER, over their permissive alternatives. Fewer valid representations means fewer opportunities for disagreement.

The artefact: a conformance corpus

The rules above are not new. They have been published in various forms for over a decade, and the bugs recur anyway.

The reason is that there is no cheap way to test for this class. A developer integrating a signature library can verify that valid signatures verify. There is no standard, portable corpus of adversarial inputs that a library is expected to reject, and so the negative cases are tested ad hoc or not at all.

A corpus would be a small artefact with disproportionate value. Proposed contents, format-parameterised:

  1. Signature removed entirely.
  2. Signature present; reference resolves to nothing.
  3. Signed element relocated into a wrapper, forged sibling in the read position.
  4. Two elements sharing one identifier.
  5. Signed element nested inside the forged one.
  6. Algorithm field set to none, to an empty string, to a case variant, to an unknown value.
  7. Asymmetric algorithm replaced by a symmetric one, public key used as the secret.
  8. Key identifier pointing outside the configured key set.
  9. Duplicate object keys with differing first and last values.
  10. The same value encoded in BER and in DER.
  11. Unicode-normalized and non-normalized forms of the same identifier.
  12. Trailing bytes appended after the signed structure.
  13. Numeric values at IEEE 754 precision boundaries.
  14. Unsigned outer envelope carrying fields that shadow signed inner ones.
  15. Valid signature over a correctly formed but expired or wrong-audience assertion, to check that verification and authorisation are separate steps.

Every case must produce the same security outcome: rejection. Unless a protocol requires distinct external responses, these cases should also share one externally observable failure class. Operations that depend on secrets must avoid secret-dependent timing.

Failure detail belongs inside the trust boundary. A verifier may need precise diagnostics in protected logs, but it should avoid exposing distinctions that create a useful oracle. The exact response policy depends on the protocol; the invariant is that parsing detail must never turn a rejected object into an accepted one.

Where this lands in practice

Three deployment patterns make the class more likely, and all three are common:

Federated identity. SAML and OIDC assertions are parsed by the service provider, and the service provider is usually not the party that chose the library. The 2025 results targeted exactly this position.

Offline signed credentials. A mobile driving licence, digital travel credential or signed QR payload may be verified by software the issuer did not write, running on devices the issuer does not control, against a schema that evolves. Every one of those gaps is a place where the verifier’s reading and the application’s reading can diverge, and the offline setting removes the possibility of a second opinion.

Supply-chain attestations. Signed build provenance is verified by tooling that then reads fields from the attestation to make policy decisions. DSSE was designed with this class in mind, which is why its pre-authentication encoding is worth studying as a positive example rather than as a curiosity.

Open work

  1. Build and publish the corpus. Cross-format, with a harness that runs it against a library and emits pass or fail per case. This is a weekend of work per format and would be immediately usable by anyone integrating a signature library. Nothing comparable exists.
  2. Survey current libraries against it. The 2012 study covered fourteen frameworks. Repeating it across today’s SAML, JWT, COSE and DSSE implementations would produce a number, and numbers are what change procurement.
  3. Measure timing and error-message differentiation across verification failures in popular libraries. Whether the oracle exists in practice is testable and unreported.
  4. Characterise the offline credential case specifically. A verifier running on a phone in the field, with no network and no telemetry, has no way to report an anomaly. What the correct failure behaviour is for that setting is genuinely unsettled.

The first item is the one worth doing. This class of bug persists not because the mitigations are unknown but because there is no cheap way to check whether they were applied, and building that check is a smaller job than the thirteen years of bypasses it would have prevented.


References

  1. Somorovsky J, Mayer A, Schwenk J, Kampmann M, Jensen M (2012). On Breaking SAML: Be Whoever You Want to Be. 21st USENIX Security Symposium
  2. The Fragile Lock: Novel Bypasses for SAML Authentication, PortSwigger Research (2025)
  3. OWASP SAML Security Cheat Sheet
  4. RFC 8785: JSON Canonicalization Scheme (JCS)
  5. RFC 7515: JSON Web Signature (JWS)
  6. RFC 9052: CBOR Object Signing and Encryption (COSE)
  7. Dead Simple Signing Envelope (DSSE) specification

Related Articles

Two embossed paper strips emerging from a precision press while a magnifier reveals their surface detail.

Sign the same message twice.

Repeated signing reveals whether output varies. Across a population, repeated ECDSA values can expose nonce reuse, compromise and implementation anomalies.