Apache Santuario (XML Security for Java) — Threat Model

§1 Header

  • Project: Apache Santuario — XML Security for Java (apache/santuario-xml-security-java), artifact org.apache.santuario:xmlsec.
  • Written against: main @ HEAD (2026-06), 4.0.x/3.0.x line.
  • Author: ASF Security team, drafted via the threat-model-producer rubric (Michael Scovetta rubric) at the Apache Santuario PMC's request (path 3).
  • Status: DRAFT — under maintainer review (2026-06-10). Not yet ratified.
  • Version binding: versioned with the project; a report against version N is triaged against the model as it stood at N.
  • Reporting cross-reference: §8-violating findings go to the disclosure channel in SECURITY.md; §3/§9 findings are closed citing this document.
  • Provenance legend: (documented) = project source / SECURITY.md / advisories (cited); (maintainer) = a Santuario maintainer in this review; (inferred) = reasoned from code/domain, not yet confirmed — each has a §14 open question.
  • Draft confidence: ~26 documented / 0 maintainer / 22 inferred.

What it is. A Java library implementing the W3C XML Signature and XML Encryption standards (plus the JSR-105 javax.xml.crypto API). It is consumed in-process by applications and frameworks (notably WS-Security stacks — WSS4J, CXF, OpenSAML/Shibboleth, Apache Santuario users in SAML/SOAP) to sign, verify, encrypt, and decrypt XML. It ships two implementations: a mature DOM-based stack and a newer StAX (streaming) stack. The security-critical operations are verification and decryption of attacker-controlled XML.

§2 Scope and intended use

Intended use: an application calls the library to verify a signature on, or decrypt, an XML document that originates outside the application's trust boundary (a SOAP message, a SAML assertion, a signed document). Equally, to produce signatures/ciphertext over its own (trusted) data.

Caller trust level: the calling application is trusted; the XML input to verification/decryption is untrusted and adversary-controlled. This is the defining trust split of the library. (inferred — Q1.)

Component families.

FamilyEntry pointProcesses untrusted XML?In model?
DOM XML Signature (verify)XMLSignature.checkSignatureValue, SignedInfoyesYes
DOM XML Encryption (decrypt)XMLCipher.doFinal / decryptDatayesYes
StAX (streaming) Sig/EncInboundXMLSec, *InputProcessoryesYes
Transforms / canonicalizationTransform, Transforms, Canonicalizeryes (transform chain runs on attacker XML)Yes
Key resolutionKeyResolver, *KeyResolverSpiyes (KeyInfo is attacker-supplied)Yes
Signing / encryption (produce)XMLSignature.sign, XMLCipher.encryptDatano — over trusted datapartial — see §3
JSR-105 API surfacejavax.xml.crypto.dsig.*as aboveYes (delegates to DOM)

§3 Out of scope (explicit non-goals)

  • Establishing trust in the verifying key. The library tells the caller “this signature is cryptographically valid under key K” and can resolve K from the message‘s KeyInfo. It does not decide whether K is trusted. Validating the certificate chain / matching K against an allow-list is the **caller’s** responsibility (§10). A report that boils down to “I trusted a self-signed cert in KeyInfo” is OUT-OF-MODEL: trusted-input / BY-DESIGN. (documented — KeyResolver returns keys; trust decisions are not in this layer.)
  • What the signature covers. The library verifies that referenced content has a valid digest; it does not decide whether the right content was signed. Checking that the signature covers the security-relevant elements (the XML-Signature-Wrapping defence) is the caller's job — see §9/§11. (documented — this is the canonical XSW caveat.)
  • Retired C++ project (santuario-xml-security-cpp) and the two archived repos — out of scope. (documented — SECURITY.md “retired”.)
  • The application's XML toolchain after extraction. Once the caller pulls decrypted/verified content out and re-parses or deserializes it, that is the caller's pipeline.

§4 Trust boundaries and data flow

The boundary is the XML document submitted for verification/decryption. Everything in that document — elements, Reference URIs, Transform chains, KeyInfo, EncryptedKey, algorithm identifiers, namespace prefixes — is attacker-controlled and must be treated as hostile.

untrusted XML (SOAP/SAML/doc)
   │  attacker controls structure, transforms, KeyInfo, algorithms
   ▼
parse (DocumentBuilderFactory — DTD handling = §8/§5a)
   ▼
Signature verify: resolve References -> run Transform chain -> canonicalize -> digest -> verify sig
   │                         ▲ XSLT/XPath transforms run here (§9 false friend)
Decrypt: resolve EncryptedKey -> KeyResolver -> unwrap -> decrypt -> (optional) re-parse
   ▼
result handed to caller  ──►  caller must check WHO signed + WHAT was signed (§10)

Reachability precondition (the triager's test): a finding is in-model only if reachable from the untrusted XML during verify/decrypt with secure validation enabled (§5a). A finding that requires secure validation to be off, or requires the caller to skip trust/coverage checks, is out of model (§5a / §3).

§5 Assumptions about the environment

  • Runtime: a conformant JRE with a JAXP XML parser and a JCE provider for the crypto primitives. The library relies on the platform parser's DTD/entity controls (§5a). (inferred — Q2.)
  • JCE provider: primitive correctness (RSA/AES/SHA, GCM nonce handling) is the provider's; the library composes them. (inferred — Q3.)
  • Concurrency: XMLSignature/XMLCipher instances are not assumed thread-safe; per-operation instances are the expected usage. (inferred — Q4.)
  • No ambient side effects beyond what a Transform/KeyResolver is configured to do — but note the default-resolver and transform behaviour can dereference URIs (§9). (inferred — Q5, high priority.)

§5a Build-time and configuration variants — the central knob

Secure validation mode is the load-bearing configuration. Santuario exposes a “secure validation” flag (e.g. XMLSignature / XMLCipher.setSecureValidation(true), the org.apache.xml.security.secureValidation property, and on by default in some JSR-105 paths). With secure validation on, the library:

  • rejects DTDs / disables external entity and RetrievalMethod/KeyInfo remote dereferencing,
  • forbids dangerous transforms (notably XSLT),
  • enforces minimum key sizes and rejects known-weak digest/MAC/signature algorithms (e.g. MD5, SHA-1-in-signatures, RSA < 1024-ish, HMAC truncation),
  • caps the number of Reference/Transform elements to bound expansion. (documented — these are the historical CVE mitigations folded into secure validation; exact set is Q-confirmed in §14.)

The insecure-default problem (must be resolved by the maintainer). Whether secure validation is on by default depends on entry point and version (the JSR-105 javax.xml.crypto path vs the native org.apache.xml.security path have differed). This reshapes §8/§9/§11a/§13 simultaneously:

  • If secure validation is the supported posture for untrusted input and a caller must opt in, then a report that only manifests with it off is OUT-OF-MODEL: non-default-build and §10 carries “enable secure validation.”
  • If it is on by default everywhere, the §8 properties hold out of the box. This is wave-1 Q6 and the most important question in the model.

§6 Assumptions about inputs

Per-parameter trust for the security-critical entry points:

Entry pointParameterAttacker-controllable?Caller must enforce
signature verifythe XML document / SignedInfoyesenable secure validation; check coverage (§10)
signature verifyKeyInfo (embedded key/cert)yesestablish trust in the resolved key — do not trust KeyInfo blindly
signature verifyReference URI / Transform chainyesrely on secure validation to bound transforms/derefs
decryptEncryptedData / EncryptedKeyyessecure validation; treat decrypted bytes as untrusted
decryptalgorithm identifiersyessecure validation enforces allow-list
sign / encryptcontent to protect, signing keyno — caller-supplied trustedprotect the private key (caller)

Plus: the parser-level inputs (DOCTYPE, entities, external refs) are attacker-controlled and governed by §5a/§8.

§7 Adversary model

  • In scope: the party that supplies the XML being verified or decrypted — a network peer in a WS-Security/SAML exchange, the sender of a signed document. Capabilities: full control of the XML structure, transforms, KeyInfo, algorithms; ability to craft signature-wrapping, transform, key- confusion, decryption-oracle, and resource-exhaustion payloads. (inferred — Q1.)
  • Out of scope: an attacker who controls the calling process or the trust/keystore configuration (they have already won); side-channel/co-tenant adversaries against the JCE provider (§5); an attacker who can make the caller disable secure validation or skip trust checks.

§8 Security properties the project provides (with secure validation on)

  1. DTD / XXE rejection. Secure validation rejects DOCTYPE and external entity resolution during parse/verify. Violation: external entity resolved / SSRF / file read. Severity: critical. (documented — secure validation; Q6 for default.)
  2. Dangerous-transform rejection. XSLT (and other code-executing/remote- deref transforms) are disallowed under secure validation. Violation: XSLT/script or remote fetch via a Transform. Severity: critical. (documented.)
  3. Weak-algorithm rejection. Known-weak digest/MAC/signature algorithms and undersized keys are rejected under secure validation. Violation: a signature accepted under MD5/short-HMAC/short-RSA. Severity: critical. (documented — folds prior CVEs.)
  4. Expansion bounding. The number of Reference/Transform elements is capped to bound CPU/memory under secure validation. Violation: super- linear blowup from many references/transforms. Severity: security (DoS). (inferred — Q7: confirm the exact caps.)
  5. Cryptographic correctness of the verify/decrypt operation given a well-formed signature and a provided key — i.e. an invalid signature does not verify true. Violation: signature forgery / bypass. Severity: critical. (documented — core function.)

§9 Security properties the project does not provide

  • It does not tell you the signature covers the right thing. A valid signature over some element is not a signature over the element your application cares about. XML Signature Wrapping (XSW) lives entirely in this gap and is the #1 real-world Santuario-adjacent vulnerability class — it is the caller's responsibility to verify that the verified Reference resolves to the security-relevant content. (documented — canonical caveat.)
    • False friend: “the signature verified” is not “the document is authentic and unmodified where it matters.”
  • It does not establish key trust. Resolving a key from KeyInfo is a convenience, not a trust decision; certificate-path validation / key pinning is the caller's (§3/§10).
  • No protection if secure validation is disabled. With it off, XXE, XSLT transforms, weak algorithms, and unbounded expansion are all reachable — by design, for backward-compatible processing of trusted XML. (documented — §5a.)
  • No decryption-oracle hardening at the protocol layer. The library performs the cryptographic decrypt; padding-oracle / replay / “decrypt-then- verify ordering” defences are protocol-level (WS-Security/SAML) concerns the caller's stack must handle. (inferred — Q8.)
  • Well-known attack classes the integrator owns: XSW (coverage checking), XXE/billion-laughs when secure validation is off, key-confusion via unvalidated KeyInfo, and decryption oracles at the protocol layer.

§10 Downstream responsibilities

  • Enable secure validation for any XML from outside your trust boundary.
  • Check what was signed — verify the signature's References resolve to the exact content you are about to trust (defeat XSW); prefer ID-based references you control and re-check post-verify.
  • Establish key trust independently — validate the cert chain / match the key against an allow-list; never trust KeyInfo-embedded keys implicitly.
  • Treat decrypted/verified bytes as untrusted until your own validation passes; apply resource limits at the boundary.
  • Protect signing/decryption private keys (caller-side key management).

§11 Known misuse patterns

  • Trusting a valid signature without checking coverage → XSW.
  • Trusting KeyInfo keys/certs without path validation → accept attacker's key.
  • Processing untrusted XML with secure validation off → XXE / XSLT / weak- algo / expansion.
  • Using verification as authorization without binding the signer identity to an authorization decision.

§11a Known non-findings (recurring false positives)

  • DocumentBuilderFactory / transform / weak-algo reachable with secure validation OFF — non-finding: off is the trusted-input posture (§5a); reachability precondition (secure validation on) not met. OUT-OF-MODEL: non-default-build (pending Q6).
  • “KeyInfo lets an attacker supply a key” — non-finding: key trust is the caller's (§3/§9). BY-DESIGN.
  • “A valid signature didn't protect element X” where X wasn‘t referenced — non-finding: coverage checking is the caller’s (§9). BY-DESIGN / VALID-HARDENING only if the API makes the safe check unreasonably hard.
  • Findings in the retired C++ project / archived reposOUT-OF-MODEL: unsupported-component (§3).
  • JCE-provider primitive issues (RNG, GCM) — out of layer (§5).

§12 Conditions that would change this model

  • A change to secure-validation defaults or the set of checks it performs (§5a).
  • A new transform/canonicalization algorithm, or a new key-resolver that dereferences remote material.
  • The StAX stack diverging from the DOM stack on any §8 property.
  • A report that cannot be routed to a §13 disposition → revise §8/§9.

§13 Triage dispositions

DispositionMeaningLicensed by
VALIDA §8 property breaks with secure validation on, via untrusted XML.§8, §6, §7
VALID-HARDENINGNo §8 break, but the API makes a §11 misuse (esp. XSW coverage) too easy.§11
OUT-OF-MODEL: trusted-inputRequires attacker control of key-trust / config the model trusts.§6
OUT-OF-MODEL: adversary-not-in-scopeRequires an excluded capability.§7
OUT-OF-MODEL: non-default-buildOnly manifests with secure validation off.§5a
OUT-OF-MODEL: unsupported-componentRetired C++ / archived repos.§3
BY-DESIGN: property-disclaimedKey trust, coverage checking, protocol oracles.§9
KNOWN-NON-FINDINGMatches §11a.§11a
MODEL-GAPUnroutable.triggers §12

§14 Open questions for the maintainers

Wave 1 — the load-bearing ones.

  • Q1. Confirm the trust split: calling application trusted; the XML submitted to verify/decrypt is fully attacker-controlled; the in-scope adversary is the XML supplier. (§2/§4/§7.)
  • Q6. Secure validation defaults — for each entry point (native org.apache.xml.security vs JSR-105 javax.xml.crypto, DOM vs StAX, and by version), is secure validation on by default, or must the caller opt in? This decides whether secure-validation-off findings are VALID or OUT-OF-MODEL: non-default-build. (§5a/§8/§9/§11a/§13.)
  • Q-XSW. Confirm the project‘s official position that **signature-coverage checking (XSW defence) is the caller’s responsibility**, and point at the canonical guidance you want cited when closing XSW reports. (§9/§10.)

Wave 2 — the secure-validation checklist (confirm/correct the §8 list).

  • Q7. Exact set enforced by secure validation: which algorithms/key sizes are rejected, which transforms are forbidden, and the caps on Reference/Transform counts? (§8.)
  • Q3/Q5. Which transforms or key-resolvers can dereference remote/local URIs, and are any enabled even under secure validation? (§5/§8/§9.)
  • Q8. Do you make any protocol-level guarantee (decryption-oracle, replay, decrypt/verify ordering), or is that explicitly the WS-Security/SAML caller's layer? (§9.)

Wave 3 — surface & coexistence.

  • Q2/Q4. Parser/JCE assumptions and thread-safety expectations. (§5.)
  • Q9. This adds THREAT_MODEL.md + AGENTS.md alongside your existing SECURITY.md (which we kept). Confirm the disclosure pointer and whether the model should become canonical with SECURITY.md linking to it. (§1/§15.)

§15 Appendix — existing-policy back-map

The repo's SECURITY.md is a disclosure-process + supported-versions policy (no embedded threat model); it points at the ASF security process and the published advisories at santuario.apache.org/secadv.html. This THREAT_MODEL.md is additive — SECURITY.md is preserved and gains a pointer to the model. The published advisories are a high-value source for refining §8/§11a in a later pass (each historical CVE maps to a secure-validation mitigation).