Skip to content

Secure APIs against XEE Attacks (XML Injection Attacks)

Learn how to secure your APIs against XML External Entity (XEE) attacks, including XML Injection and XML Expansion attacks, with practical mitigation steps for Java and RestEasy.

TL;DR

  • XXE/XEE is an API-level vulnerability: Any Java service that parses XML input is potentially exposed unless you explicitly disable external entity resolution
  • Disable DTDs entirely: The safest mitigation is blocking DOCTYPE declarations altogether, which prevents both XML injection and XML expansion attacks
  • SAXParserFactory is the right approach: OWASP continues to recommend explicit feature flags on SAXParserFactory for Java applications; this has not changed
  • Default Java parsers are not safe: Most Java XML parsers have external entity processing enabled by default; you must configure them explicitly

What You'll Learn

  • What XXE and XEE attacks are and why XML-consuming APIs are vulnerable
  • The difference between XML injection (entity) attacks and XML expansion (billion laughs) attacks
  • How to configure SAXParserFactory correctly to block both attack types
  • How to wire the hardened parser into a RestEasy MessageBodyReader

The Problem

Any web API that accepts XML payloads and parses them server-side is a potential target for XXE (XML External Entity) attacks. The vulnerability exists because the XML specification allows documents to reference external resources (URLs, file paths, or inline expansions) and most parsers resolve those references by default.

What an attacker can achieve:

  • Server-Side Request Forgery (SSRF): An injected external entity pointing to an internal URL (http://169.254.169.254/) causes your server to make outbound requests on the attacker's behalf
  • File disclosure: An entity referencing file:///etc/passwd can return the file's contents in the XML response
  • Denial of Service: Recursive entity definitions (the "Billion Laughs" / LOL attack) cause exponential memory expansion and crash the server
  • Blind SSRF: Entities that reference URLs that never respond cause your parser threads to hang indefinitely

The vulnerability is particularly dangerous in Java because most XML parsers (including SAXParser, DocumentBuilder, and the JAXB/RestEasy unmarshalling pipeline) have external entity resolution enabled by default.

Quick Answer

Configure SAXParserFactory with these six feature flags before creating any parser instance:

SAXParserFactory factory = SAXParserFactory.newInstance();

// Disable external general entity resolution (e.g., external URLs in DTD)
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);

// Disable external parameter entity resolution
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

// Block DOCTYPE declarations entirely (prevents XML expansion attacks)
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

// Enable secure processing mode (resource limits, disables some features)
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

// Disable validation (reduces attack surface)
factory.setFeature("http://xml.org/sax/features/validation", false);

// Enable namespace processing (required for correct JAXB operation)
factory.setFeature("http://xml.org/sax/features/namespaces", true);

Disabling DOCTYPE declarations (disallow-doctype-decl) is the most effective single control: it blocks both entity injection and billion-laughs expansion in one flag. If your XML payloads legitimately use DOCTYPE, disable just the external entity features instead.

Types of XEE Attacks

  • XML Injection Attacks: Involve external URL or schema file references in the XML payload. These can lead to Denial of Service (DoS) if they point to URLs that never return, or potentially allow access to server files if file system access is not properly restricted.
  • XML Expansion Attacks: Use recursive or very large doctype references in the XML payload, such as the "LOL attack," to consume server resources.

Mitigation for RestEasy (Java)

To secure APIs, especially when using RestEasy, implement a custom javax.ws.rs.ext.MessageBodyReader<Object> and configure the javax.xml.bind.Unmarshaller instance with specific security features.

The recommended SAXParserFactory settings to prevent XEE attacks are:

  • factory.setFeature("http://xml.org/sax/features/validation", false);
  • factory.setFeature("http://xml.org/sax/features/namespaces", true);
  • factory.setFeature("http://xml.org/sax/features/external-general-entities", false); (Crucial for preventing external entity resolution)
  • factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); (Crucial for preventing external parameter entity resolution)
  • factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); (Enables secure processing)
  • factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); (Prevents Doctype declarations, mitigating XML Expansion attacks)

The article concludes by showing how to use the configured XMLReader with an Unmarshaller and SAXSource to safely unmarshal XML input.

Frequently Asked Questions

Q: What's the difference between XXE and XEE?

A: The terms are often used interchangeably in practice. XXE stands for XML External Entity, the canonical OWASP term for the class of vulnerabilities involving external entity resolution in XML. XEE is an alternate abbreviation (XML External Entity) sometimes used in older literature, including earlier versions of this post. Both refer to the same family of attacks. This post uses "XEE" to match the original title but the OWASP cheat sheet, CVE database, and most current tooling use "XXE."

Q: Does Java's default XML parser block XXE?

A: No. The Java standard library XML parsers (SAXParserFactory, DocumentBuilderFactory, XMLInputFactory) have external entity processing enabled by default. This has been a longstanding Java platform design decision for backwards compatibility. OWASP explicitly notes that "most Java XML parsers have XXE enabled by default" and that you must configure them explicitly. This applies to all current LTS Java versions (11, 17, 21).

Q: How do I test for XXE vulnerabilities?

A: Several approaches:

  • Manual testing: Submit an XML payload containing a DOCTYPE with an external entity pointing to an internal URL or file:// path. Check whether the response reflects the entity value.
  • Burp Suite: The Burp Scanner includes XXE detection. The Burp Collaborator can detect out-of-band XXE where the response does not directly reflect the injected content.
  • OWASP ZAP: Includes an XXE active scan rule.
  • Unit testing: Write a test that submits a known XXE payload to your MessageBodyReader and asserts that an exception is thrown or the entity is not resolved.

Q: Does FEATURE_SECURE_PROCESSING alone protect against XXE?

A: Partially but not completely. XMLConstants.FEATURE_SECURE_PROCESSING enables resource limits and may restrict some processing, but OWASP notes it does not reliably block all XXE vectors. You still need to explicitly disable the external entity features and, if possible, disallow DOCTYPE declarations. Use FEATURE_SECURE_PROCESSING as an additional layer, not the primary control.

Q: What if my application legitimately uses DTD or external schemas?

A: If you cannot block DOCTYPE declarations entirely, at minimum disable external general and parameter entities:

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

Also disable loading of external DTDs via the loadExternalDTD feature:

factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

Key Takeaways

  • XXE is a default-on risk in Java: Every Java XML parser resolves external entities unless you explicitly disable them. Assuming default behaviour is safe is the root cause of most XXE vulnerabilities
  • Disable DTDs if you can: Setting disallow-doctype-decl to true is the most comprehensive single control and blocks both injection and expansion attacks in one flag
  • Layer your controls: Combine disallow-doctype-decl, external entity features, and FEATURE_SECURE_PROCESSING for defence in depth
  • Apply at the factory level: Configure features on the SAXParserFactory before creating the parser (not on the XMLReader instance alone) so the settings apply consistently across all parsers created from that factory
  • Test explicitly: Include XXE payloads in your security test suite rather than relying on code review alone

What's Next?

Recommended Reading:

Action Items:

  1. Search your codebase for all usages of SAXParserFactory, DocumentBuilderFactory, and XMLInputFactory. These are the three most common Java XXE entry points
  2. Apply the feature flags from the Quick Answer section to each factory instantiation
  3. Add an XXE test payload to your API integration test suite to verify the configuration is effective
  4. Review any third-party libraries that consume XML on your behalf. They may have their own parser configuration requirements

Resources & References