Skip to main content

XXE - XML External Entity Processing

An XML parser is configured to resolve external entities, so an attacker's document can name a SYSTEM entity and make the parser read a local file or send a request from the server. Findings are reported under API8:2023 Security Misconfiguration.

What Vulkro detects​

Configuration shapes read from the parser construction; the parser is never run.

RuleLanguageFires onSeverity
(lxml check)Pythonlxml.etree.XMLParser with resolve_entities=True, no_network=False or load_dtd=TrueHigh, High confidence
XXE-PY-001Pythonxml.sax with the external general or parameter entity feature enabled; suppressed when the file imports defusedxmlHigh
XXE-JS-001JavaScriptlibxmljs / libxmljs2 parse with noent: trueHigh
XXE-JS-002JavaScriptxmldom / @xmldom/xmldom DOMParser().parseFromString(...); heuristic (runtime version not visible)Medium
XXE-GO-001Goa parse through a third-party libxml2 binding (stdlib encoding/xml is safe); heuristicMedium
JAVA-XXE-001Javaa JAXP factory, dom4j SAXReader or JDOM SAXBuilder parses a request-derived value in a file with no hardeningHigh, Medium confidence
JAVA-XXE-002Javaa method that builds a parser and parses one of its own parameters with no unconditional hardening (no taint needed)Medium, Medium confidence
JAVA-XXE-003Javaa call site passing a request-derived value to a helper flagged by JAVA-XXE-002High, Medium confidence

Java: unconditional hardening anywhere in the file silences JAVA-XXE-001; hardening inside a branch (if (x) { ... }) does not count (Allman-style braces are a known gap). JAVA-XXE-003 needs a matching receiver type, method name and tainted argument; unresolved receivers are skipped.

A finding means the parser resolves external entities (in Java: no visible hardening), not that an exploit exists. Billion-laughs denial of service is a separate, lower-severity signal.

Non-compliant code​

# lxml parser with every protection off
from lxml import etree
parser = etree.XMLParser(resolve_entities=True, load_dtd=True, no_network=False)
doc = etree.fromstring(request_body, parser) # SYSTEM entities resolve

Compliant code​

from defusedxml.lxml import fromstring
doc = fromstring(request_body)

How to fix​

  • Python: defusedxml, or lxml with resolve_entities=False, load_dtd=False, no_network=True.
  • Java: set disallow-doctype-decl and FEATURE_SECURE_PROCESSING on the factory.
  • libxml2: no NOENT, network off. Go: stdlib encoding/xml.

References​

See also: Confidence model.


This page is generated by vulkro rules export <out-dir> from Vulkro's built-in detector catalogue. Edits made by hand are overwritten on the next regeneration.