Defaults change between libraries and versions, so set the policy in code where reviewers can see it. In Java, the OWASP XXE Prevention Cheat Sheet's recommended configuration disallows DOCTYPE declarations entirely:
import java.io.ByteArrayInputStream;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
public class SafeParser {
static DocumentBuilderFactory hardened() throws Exception {
var f = DocumentBuilderFactory.newInstance();
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // no DTDs
f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); // JDK limits on
f.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // nor fetches
f.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // or schemas
f.setXIncludeAware(false);
f.setExpandEntityReferences(false);
return f;
}
public static void main(String[] args) throws Exception {
String[] docs = {"<catalog><book id='b1'/></catalog>",
"<!DOCTYPE b [<!ENTITY shop 'BookNest'>]><b>&shop;</b>"};
for (String xml : docs) {
try {
var doc = hardened().newDocumentBuilder()
.parse(new ByteArrayInputStream(xml.getBytes()));
System.out.println("parsed <" + doc.getDocumentElement().getTagName() + ">");
} catch (org.xml.sax.SAXParseException e) {
System.out.println("rejected: " + e.getMessage());
}
}
}
}Output
parsed <catalog> rejected: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-docty pe-decl" set to true.
| Library | Safe configuration |
|---|---|
| Python stdlib | Use defusedxml (forbid_dtd=True for feeds) |
| lxml 3,063 | XMLParser(resolve_entities=False, no_network=True), no huge_tree |
| Java JAXP | disallow-doctype-decl, FEATURE_SECURE_PROCESSING, no XInclude |
| .NET | XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit |
| libxml2 3,427 , PHP | Never pass XML_PARSE_NOENT/LIBXML_NOENT or DTDLOAD |
Validate against a schema you ship (XSD 1.1 Types-Schematron), never one the incoming document names.