From 207217290a4de35386444c32c5c52cf97c4e9b5e Mon Sep 17 00:00:00 2001 From: Stefano Cordio Date: Sat, 24 Jan 2026 19:47:47 +0100 Subject: [PATCH] Merge commit from fork --- .../util/xml/XmlStringPrettyFormatter.java | 27 +++++++++++++- ...ringPrettyFormatter_prettyFormat_Test.java | 35 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java b/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java index 0956ddf8b..bbec9106e 100644 --- a/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java +++ b/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java @@ -17,9 +17,13 @@ import static org.assertj.core.util.Preconditions.checkArgument; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; +import java.util.HashMap; +import java.util.Map; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.bootstrap.DOMImplementationRegistry; @@ -39,6 +43,17 @@ public class XmlStringPrettyFormatter { private static final String FORMAT_ERROR = "Unable to format XML string"; + // https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html + private static final Map SECURE_FEATURES = new HashMap<>(); + + static { + SECURE_FEATURES.put(XMLConstants.FEATURE_SECURE_PROCESSING, true); + SECURE_FEATURES.put("http://apache.org/xml/features/disallow-doctype-decl", true); + SECURE_FEATURES.put("http://xml.org/sax/features/external-general-entities", false); + SECURE_FEATURES.put("http://xml.org/sax/features/external-parameter-entities", false); + SECURE_FEATURES.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } + public static String xmlPrettyFormat(String xmlStringToFormat) { checkArgument(xmlStringToFormat != null, "Expecting XML String not to be null"); // convert String to an XML Document and then back to String but prettily formatted. @@ -67,13 +82,23 @@ public class XmlStringPrettyFormatter { private static Document toXmlDocument(String xmlString) { try { InputSource xmlInputSource = new InputSource(new StringReader(xmlString)); - DocumentBuilder xmlDocumentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + DocumentBuilder xmlDocumentBuilder = documentBuilderFactory().newDocumentBuilder(); return xmlDocumentBuilder.parse(xmlInputSource); } catch (Exception e) { throw new RuntimeException(FORMAT_ERROR, e); } } + private static DocumentBuilderFactory documentBuilderFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + SECURE_FEATURES.forEach((name, value) -> { + try { + factory.setFeature(name, value); + } catch (ParserConfigurationException ignore) {} + }); + return factory; + } + private XmlStringPrettyFormatter() { // utility class } diff --git a/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java b/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java index c2c3e574d..21f00df42 100644 --- a/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java +++ b/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java @@ -97,4 +97,39 @@ class XmlStringPrettyFormatter_prettyFormat_Test { } } + @Test + void should_fail_if_input_contains_doctype_declaration_with_entity() { + // Injection into document content + String xmlString = "\n" + + "\n" + + "]>\n" + + "&xxe;"; + try { + xmlPrettyFormat(xmlString); + } catch (Exception e) { + assertThat(e).isInstanceOf(RuntimeException.class).hasMessage("Unable to format XML string"); + assertThat(e.getCause()).isInstanceOf(SAXParseException.class) + .hasMessageContaining("DOCTYPE is disallowed"); + } + } + + @Test + void should_fail_if_input_contains_doctype_declaration_with_parameter_entity() { + // Injection during document parsing + String xmlString = "\n" + + "\n" + + " %xxe;\n" + + "]>\n" + + "foo"; + try { + xmlPrettyFormat(xmlString); + } catch (Exception e) { + assertThat(e).isInstanceOf(RuntimeException.class).hasMessage("Unable to format XML string"); + assertThat(e.getCause()).isInstanceOf(SAXParseException.class) + .hasMessageContaining("DOCTYPE is disallowed"); + } + } + } -- 2.52.0