Add a patch to fix CVE-2026-24400 by enabling secure XML
parsing features in XmlStringPrettyFormatter. The patch
disables DOCTYPE declarations and external entity processing
to prevent XXE (XML External Entity) attacks. Backported from
upstream commit 77081dc5eb107141df80f95bd0149b468e451341,
adapted for the 3.24.2 source tree. Includes two new test
cases verifying that XML strings containing DOCTYPE with
general and parameter entities are properly rejected.
CVE: CVE-2026-24400
Upstream patches:
- 77081dc5eb.patch
Resolves: RHEL-208838
This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.
Assisted-by: Ymir
121 lines
5.3 KiB
Diff
121 lines
5.3 KiB
Diff
From a89c9ad8443985ee4dd05452b7a589328fa3b157 Mon Sep 17 00:00:00 2001
|
|
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
|
|
Date: Thu, 25 Jun 2026 12:40:54 +0000
|
|
Subject: [PATCH] Add XXE protection to XmlStringPrettyFormatter
|
|
|
|
Add secure XML parsing features to prevent XXE attacks by disabling
|
|
DOCTYPE declarations and external entity processing.
|
|
|
|
Adapted for 3.24.2: keep tests in the old location.
|
|
---
|
|
.../util/xml/XmlStringPrettyFormatter.java | 27 ++++++++++++++-
|
|
...ringPrettyFormatter_prettyFormat_Test.java | 33 +++++++++++++++++++
|
|
2 files changed, 59 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/assertj-core/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java b/assertj-core/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java
|
|
index 33c035b33..b66b9858b 100644
|
|
--- a/assertj-core/src/main/java/org/assertj/core/util/xml/XmlStringPrettyFormatter.java
|
|
+++ b/assertj-core/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/assertj-core/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java b/assertj-core/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java
|
|
index 2c1bf754e..1600e1306 100644
|
|
--- a/assertj-core/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java
|
|
+++ b/assertj-core/src/test/java/org/assertj/core/util/xml/XmlStringPrettyFormatter_prettyFormat_Test.java
|
|
@@ -97,4 +97,37 @@ class XmlStringPrettyFormatter_prettyFormat_Test {
|
|
}
|
|
}
|
|
|
|
+ @Test
|
|
+ void should_throw_error_when_xml_string_contains_doctype_with_entity() {
|
|
+ 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).hasMessageStartingWith("Unable to format XML string");
|
|
+ assertThat(e).hasRootCauseInstanceOf(SAXParseException.class);
|
|
+ assertThat(e.getCause()).hasMessageContaining("DOCTYPE is disallowed");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void should_throw_error_when_xml_string_contains_doctype_with_parameter_entity() {
|
|
+ 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).hasMessageStartingWith("Unable to format XML string");
|
|
+ assertThat(e).hasRootCauseInstanceOf(SAXParseException.class);
|
|
+ assertThat(e.getCause()).hasMessageContaining("DOCTYPE is disallowed");
|
|
+ }
|
|
+ }
|
|
+
|
|
}
|
|
--
|
|
2.52.0
|
|
|