Skip to content

VNX-JAVA-029: XML External Entity (XXE) via DocumentBuilderFactory

Detects DocumentBuilderFactory, SAXParserFactory and XMLReaderFactory parsers that are never hardened (disallow-doctype-decl, external-general-entities false, secure processing or ACCESS_EXTERNAL_DTD), and external entities explicitly switched on. StAX, TransformerFactory and SchemaFactory are covered by VNX-JAVA-004.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-JAVA-029
Severity High
SARIF level error
Kind sast
Languages Java
CWE CWE-611
CAPEC CAPEC-183
ATT&CK T1195.002
CWSS vector CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H
Tags xxe xml parsing
Source internal/sast/rules/vnx-java-029.rego

Overview

This rule reports the line that creates a DocumentBuilderFactory, SAXParserFactory or XMLReaderFactory.createXMLReader() parser when the file never hardens it: no setFeature(disallow-doctype-decl, true), setFeature(external-general-entities, false), setFeature(FEATURE_SECURE_PROCESSING, true) or setAttribute(ACCESS_EXTERNAL_DTD, "") on that variable (a feature URI held in a constant counts), none on a parser or reader derived from it within the next 30 lines, and no secure(...)/harden(...) helper given the factory. A factory created and used in one chained expression is reported. It also reports setFeature(external-general-entities, true) on a parser that does not restrict ACCESS_EXTERNAL_DTD. setExpandEntityReferences(false) alone is not accepted as hardening. Imports, comments and string literals are not reported. By default, many JDK XML parser implementations will resolve external entity references declared in a document’s DTD. When an application parses untrusted XML with these defaults, an attacker can supply a crafted XML document that causes the parser to read local files, make outbound network requests, or exhaust server resources through entity expansion (Billion Laughs). This vulnerability is classified as CWE-611 (Improper Restriction of XML External Entity Reference).

The Java standard library ships with multiple XML parsing APIs, DOM (DocumentBuilderFactory), SAX (SAXParserFactory), and StAX, each with its own feature flags for controlling entity processing. Configuring each correctly requires explicit, non-obvious setFeature() calls that are easy to omit, especially when copying boilerplate parsing code. JDK versions prior to 8u191 had XXE-safe defaults in some APIs but not others; relying on JDK version for safety is fragile.

Why This Matters

XXE attacks can lead to server-side file disclosure (/etc/passwd, application config files, private keys), Server-Side Request Forgery (SSRF) to internal services including cloud metadata endpoints, denial of service via recursive entity expansion, and in some configurations remote code execution. SAML authentication libraries parsing XML assertions have historically been prime XXE targets, a successful XXE in a SAML processor can lead to complete authentication bypass.

The impact is amplified in containerized or cloud environments where the application process has access to instance metadata services (AWS http://169.254.169.254, GCP, Azure equivalents). An attacker who retrieves IAM credentials via XXE gains the cloud permissions of the application’s service identity, potentially enabling lateral movement across the entire cloud account.

What Gets Flagged

// FLAGGED: DocumentBuilderFactory with no XXE mitigations
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(req.getInputStream()));

// FLAGGED: SAXParserFactory without feature hardening
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
parser.parse(inputStream, handler);

// FLAGGED: XMLReader without disabling external entities
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.parse(new InputSource(untrustedInput));

Remediation

  1. Set http://apache.org/xml/features/disallow-doctype-decl to true on the factory. This is the most complete mitigation, it rejects any XML document containing a DOCTYPE declaration, eliminating the attack surface entirely.
  2. If DOCTYPE is required, additionally disable external general and parameter entities via their respective feature flags.
  3. Wrap setFeature() calls in a try/catch for ParserConfigurationException to handle JDK implementations that do not support a specific feature string, fail closed by throwing an exception rather than continuing with an unsafe parser.
  4. Consider using a safe wrapper library (OWASP’s XML security utilities) that applies hardened defaults automatically.
// SAFE: DocumentBuilderFactory with XXE disabled
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

// Disallow DOCTYPE entirely, most complete protection
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// Belt-and-suspenders: also disable external entities if DOCTYPE slips through
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);

DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(req.getInputStream()));

// SAFE: SAXParserFactory equivalent
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser parser = spf.newSAXParser();

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-java-029
// nosec vnx-java-029

Or record an ignore rule: vulnetix ignore add --rule vnx-java-029 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-java-029.rego, cli/internal/sast/docs/vnx-java-029.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.