Backport upstream commit 77081dc5e to assertj-core 3.19.0 to
fix CVE-2026-24400. The patch hardens XmlStringPrettyFormatter
against XML External Entity (XXE) attacks by enabling
FEATURE_SECURE_PROCESSING and disallowing DOCTYPE declarations
in the XML parser configuration. Two new tests verify that
inputs containing DOCTYPE declarations with entity and
parameter entity injections are properly rejected.
CVE: CVE-2026-24400
Upstream patches:
- 77081dc5eb.patch
Resolves: RHEL-208834
This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.
Assisted-by: Ymir
119 lines
5.1 KiB
Diff
119 lines
5.1 KiB
Diff
From 207217290a4de35386444c32c5c52cf97c4e9b5e Mon Sep 17 00:00:00 2001
|
|
From: Stefano Cordio <stefano.cordio@gmail.com>
|
|
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<String, Boolean> 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 = "<?xml version=\"1.0\"?>\n"
|
|
+ + "<!DOCTYPE root [\n"
|
|
+ + " <!ENTITY xxe SYSTEM \"file:///etc/hosts\">\n"
|
|
+ + "]>\n"
|
|
+ + "<root>&xxe;</root>";
|
|
+ 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 = "<?xml version=\"1.0\"?>\n"
|
|
+ + "<!DOCTYPE root [\n"
|
|
+ + " <!ENTITY % xxe SYSTEM \"file:///etc/hosts\">\n"
|
|
+ + " %xxe;\n"
|
|
+ + "]>\n"
|
|
+ + "<root>foo</root>";
|
|
+ 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
|
|
|