assertj-core/assertj-core-3.24.2-CVE-2026-24400.patch
RHEL Packaging Agent 55e257df96 Fix CVE-2026-24400: XXE vulnerability in assertj-core
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
2026-07-17 14:55:58 +02:00

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