1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
Description: CVE-2025-54812 - part 1 - Improper HTML escaping in HTMLLayout
Origin: https://github.com/apache/logging-log4cxx/commit/1c599de956ae9eedd8b5e3f744bfb867c39e8bba
Bug: https://logging.apache.org/security.html#CVE-2025-54812
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1111879
From 1c599de956ae9eedd8b5e3f744bfb867c39e8bba Mon Sep 17 00:00:00 2001
From: Stephen Webb <stephen.webb@ieee.org>
Date: Sat, 12 Jul 2025 10:19:03 +1000
Subject: [PATCH] Escape any logger name '&' or '"' in html attribute data
(#509)
---
src/main/cpp/htmllayout.cpp | 8 ++---
src/test/cpp/xml/xmllayouttest.cpp | 49 ++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/src/main/cpp/htmllayout.cpp b/src/main/cpp/htmllayout.cpp
index c2411ece9..ed6e61d76 100644
--- a/src/main/cpp/htmllayout.cpp
+++ b/src/main/cpp/htmllayout.cpp
@@ -109,25 +109,25 @@ void HTMLLayout::format(LogString& output,
if (event->getLevel()->equals(Level::getDebug()))
{
output.append(LOG4CXX_STR("<font color=\"#339933\">"));
- output.append(event->getLevel()->toString());
+ Transform::appendEscapingTags(output, event->getLevel()->toString());
output.append(LOG4CXX_STR("</font>"));
}
else if (event->getLevel()->isGreaterOrEqual(Level::getWarn()))
{
output.append(LOG4CXX_STR("<font color=\"#993300\"><strong>"));
- output.append(event->getLevel()->toString());
+ Transform::appendEscapingTags(output, event->getLevel()->toString());
output.append(LOG4CXX_STR("</strong></font>"));
}
else
{
- output.append(event->getLevel()->toString());
+ Transform::appendEscapingTags(output, event->getLevel()->toString());
}
output.append(LOG4CXX_STR("</td>"));
output.append(LOG4CXX_EOL);
output.append(LOG4CXX_STR("<td title=\""));
- output.append(event->getLoggerName());
+ Transform::appendEscapingTags(output, event->getLoggerName());
output.append(LOG4CXX_STR(" logger\">"));
Transform::appendEscapingTags(output, event->getLoggerName());
output.append(LOG4CXX_STR("</td>"));
diff --git a/src/test/cpp/xml/xmllayouttest.cpp b/src/test/cpp/xml/xmllayouttest.cpp
index 78f1c1183..710e9fca4 100644
--- a/src/test/cpp/xml/xmllayouttest.cpp
+++ b/src/test/cpp/xml/xmllayouttest.cpp
@@ -18,6 +18,7 @@
#include "../logunit.h"
#include <log4cxx/logger.h>
#include <log4cxx/xml/xmllayout.h>
+#include <log4cxx/htmllayout.h>
#include <log4cxx/fileappender.h>
#include <log4cxx/mdc.h>
@@ -37,6 +38,7 @@
#include "../xml/xlevel.h"
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/helpers/transcoder.h>
+#include <log4cxx/helpers/loglog.h>
using namespace log4cxx;
@@ -67,6 +69,7 @@ LOGUNIT_CLASS(XMLLayoutTest)
LOGUNIT_TEST(testActivateOptions);
LOGUNIT_TEST(testProblemCharacters);
LOGUNIT_TEST(testNDCWithCDATA);
+ LOGUNIT_TEST(testHTMLLayout);
LOGUNIT_TEST_SUITE_END();
@@ -453,6 +456,52 @@ LOGUNIT_CLASS(XMLLayoutTest)
LOGUNIT_ASSERT_EQUAL(1, ndcCount);
}
+ /**
+ * Tests problematic characters in multiple fields.
+ * @throws Exception if parser can not be constructed or source is not a valid XML document.
+ */
+ void testHTMLLayout()
+ {
+ LogString problemName = LOG4CXX_STR("com.example.bar<>&\"'");
+ auto level = std::make_shared<XLevel>(6000, problemName, 7);
+ NDC context(problemName);
+ auto event = std::make_shared<LoggingEvent>(problemName, level, problemName, LOG4CXX_LOCATION);
+
+ HTMLLayout layout;
+ Pool p;
+ LogString html(LOG4CXX_STR("<body>"));
+ layout.format(html, event, p);
+ html += LOG4CXX_STR("</body>");
+
+ LogLog::debug(html);
+ char backing[3000];
+ ByteBuffer buf(backing, sizeof(backing));
+ CharsetEncoderPtr encoder(CharsetEncoder::getUTF8Encoder());
+ LogString::const_iterator iter{ html.begin() };
+ encoder->encode(html, iter, buf);
+ LOGUNIT_ASSERT(iter == html.end());
+ buf.flip();
+ auto parser = apr_xml_parser_create(p.getAPRPool());
+ LOGUNIT_ASSERT(parser != 0);
+ auto stat = apr_xml_parser_feed(parser, buf.data(), buf.remaining());
+ LOGUNIT_ASSERT(stat == APR_SUCCESS);
+ apr_xml_doc* doc = 0;
+ stat = apr_xml_parser_done(parser, &doc);
+ LOGUNIT_ASSERT(doc != 0);
+ auto parsedResult = doc->root;
+ LOGUNIT_ASSERT(parsedResult != 0);
+
+ int childElementCount = 0;
+ for ( auto node = parsedResult->first_child
+ ; node != NULL
+ ; node = node->next)
+ {
+ ++childElementCount;
+ LOGUNIT_ASSERT_EQUAL(std::string("tr"), std::string(node->name));
+ }
+ LOGUNIT_ASSERT(1 < childElementCount);
+ }
+
};
|