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
This commit is contained in:
RHEL Packaging Agent 2026-06-25 12:54:06 +00:00 committed by Marian Koncek
parent def7008f83
commit 55e257df96
2 changed files with 129 additions and 1 deletions

View File

@ -0,0 +1,120 @@
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

View File

@ -2,12 +2,15 @@
Name: assertj-core
Version: 3.24.2
Release: 9%{?dist}
Release: 10%{?dist}
Summary: Library of assertions similar to fest-assert
License: Apache-2.0
URL: https://joel-costigliola.github.io/assertj/
Source0: https://github.com/joel-costigliola/assertj-core/archive/assertj-build-%{version}.tar.gz
# https://github.com/assertj/assertj/commit/77081dc5eb107141df80f95bd0149b468e451341
Patch0: assertj-core-3.24.2-CVE-2026-24400.patch
BuildArch: noarch
ExclusiveArch: %{java_arches} noarch
@ -34,6 +37,7 @@ This package provides API documentation for %{name}.
%prep
%setup -q -n assertj-assertj-build-%{version}
%patch -P0 -p1
%pom_remove_plugin -r :maven-javadoc-plugin
%pom_remove_plugin -r :maven-enforcer-plugin
@ -80,6 +84,10 @@ This package provides API documentation for %{name}.
%license LICENSE.txt
%changelog
* Thu Jun 25 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 3.24.2-10
- Fix CVE-2026-24400: add XXE protection to XmlStringPrettyFormatter
- Resolves: RHEL-208838
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 3.24.2-9
- Bump release for October 2024 mass rebuild:
Resolves: RHEL-64018