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
SAXParserFactoryfor 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
SAXParserFactorycorrectly 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/passwdcan 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
MessageBodyReaderand 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-decltotrueis 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, andFEATURE_SECURE_PROCESSINGfor defence in depth - Apply at the factory level: Configure features on the
SAXParserFactorybefore creating the parser (not on theXMLReaderinstance 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:
- OWASP XXE Prevention Cheat Sheet: the authoritative reference for Java and other language-specific configurations
- OWASP XML Security Cheat Sheet: broader XML security hardening guidance
Action Items:
- Search your codebase for all usages of
SAXParserFactory,DocumentBuilderFactory, andXMLInputFactory. These are the three most common Java XXE entry points - Apply the feature flags from the Quick Answer section to each factory instantiation
- Add an XXE test payload to your API integration test suite to verify the configuration is effective
- Review any third-party libraries that consume XML on your behalf. They may have their own parser configuration requirements