CVE-2026-34479

Denial of Service
Affects
Apache Log4j 2
in
Apache Log4j
No items found.
Versions
>=2.7 <=2.25.3, >=3.0.0-beta1 <=3.0.0-beta2

Overview

Apache Log4j 2 ships a Log4j 1-to-Log4j 2 compatibility bridge in the log4j-1.2-api artifact, which lets applications written against the Log4j 1 API (or that load Log4j 1 XML configuration files) keep running on top of the Log4j 2 runtime. The bridge re-implements Log4j 1's XML layout class as org.apache.log4j.layout.Log4j1XmlLayout, which formats each log event as a <log4j:event> element with attributes for logger, level, and thread, plus child elements (<log4j:message>, <log4j:NDC>, <log4j:throwable>, <log4j:locationInfo>, <log4j:properties>) carrying the message body, MDC entries, exception text, and source-location metadata.

A medium-severity vulnerability (CVE-2026-34479, classified as CWE-116 Improper Encoding or Escaping of Output) has been identified in Log4j1XmlLayout. The layout writes attributes through org.apache.logging.log4j.core.util.Transform.escapeHtmlTags(...) and child-element CDATA payloads through Transform.appendEscapingCData(...). Neither helper sanitizes Unicode code points that XML 1.0 forbids in character content: most C0 controls (U+0000U+0008, U+000B, U+000C, U+000EU+001F), unpaired surrogates in U+D800U+DFFF, and the non-characters U+FFFE / U+FFFF. When such a code point appears in any field that flows from attacker-controlled input (a log message, exception text, MDC value, logger name, thread name, or source class/method/file), the resulting <log4j:event> document is not well-formed per the XML 1.0 specification. Conforming XML parsers in downstream log collectors, log shippers, ELK/OpenSearch ingest pipelines, and SIEM platforms must reject the document with a fatal error, so the affected record (and depending on the parser's recovery semantics, subsequent records in the same buffer) is silently dropped from the audit trail.

Per OWASP: "Denial of Service (DoS) is an attack against the availability of a system or service." A logging-pipeline DoS attack is particularly damaging because it removes the operator's primary visibility into other attacks: a single forbidden character in a request header can cause the very record that would have flagged the attacker's actions to be discarded before it reaches the SIEM.

The CVSS v4.0 base score is 6.9 (Medium) with vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:N. There is no impact on the running application's confidentiality, integrity, or availability; the integrity of the *subsequent system* (the log consumer) is degraded because expected events go missing. The attack requires no privileges and no user interaction, and the attack vector is broad: anything that lands in a logged field counts, including HTTP headers, query parameters, JSON request bodies, exception messages, and MDC entries.

This issue affects Apache Log4j 2 versions 2.7 through 2.25.3 (the lower bound matches when Log4j1XmlLayout was first added to log4j-1.2-api), and pre-release versions 3.0.0-beta1 through 3.0.0-beta2.

Details

Module Info

Vulnerability Info

The vulnerability is in org.apache.log4j.layout.Log4j1XmlLayout (the Log4j 1-to-Log4j 2 compat bridge's XML layout) by way of the shared output-encoding utility org.apache.logging.log4j.core.util.Transform in log4j-core. Two helpers in Transform are reachable from every emit path of Log4j1XmlLayout: escapeHtmlTags(String) (used for XML attribute values) and appendEscapingCData(StringBuilder, String) (used for child-element CDATA payloads).

An application is vulnerable when all of the following are true:

  • The application uses Apache Log4j 2 between 2.7 and 2.25.3 inclusive (or a 3.x pre-release in the affected range)
  • The application uses Log4j1XmlLayout directly in a Log4j Core 2 configuration file, or routes through the Log4j 1 configuration compatibility layer with org.apache.log4j.xml.XMLLayout specified as the layout class
  • An attacker can influence any string that ends up in a logged LogEvent field (the attack surface is broad: HTTP headers, query parameters, request bodies, exception text, MDC values, etc.)
  • The resulting XML log records are consumed by a strict XML parser downstream (typical of SIEMs, log shippers, and audit pipelines)

When those conditions are met, the attacker can inject a single C0 control byte, lone surrogate, or U+FFFE / U+FFFF into any logged field; the layout copies that code point into the <log4j:event> document; and the downstream parser drops the record.

Prior to the fix, Transform.escapeHtmlTags only entity-escaped <, >, &, and " (notably skipping ') and emitted any character with code point greater than '>' (0x3E) verbatim, including the entire C1 control range, lone surrogate halves, and U+FFFE / U+FFFF:

public static String escapeHtmlTags(final String input) {
    if (Strings.isEmpty(input)
            || (input.indexOf('"') == -1
                    && input.indexOf('&') == -1
                    && input.indexOf('<') == -1
                    && input.indexOf('>') == -1)) {
        return input;
    }
    final StringBuilder buf = new StringBuilder(input.length() + 6);
    final int len = input.length();
    for (int i = 0; i < len; i++) {
        final char ch = input.charAt(i);
        if (ch > '>') {
            buf.append(ch);
        } else
            switch (ch) {
                case '<': buf.append("&lt;"); break;
                case '>': buf.append("&gt;"); break;
                case '&': buf.append("&amp;"); break;
                case '"': buf.append("&quot;"); break;
                default:  buf.append(ch); break;
            }
    }
    return buf.toString();
}

Transform.appendEscapingCData was even more permissive: it copied the entire CDATA payload byte-for-byte, splitting only at ]]> to avoid prematurely closing the section. CDATA only protects from </>/&, not from XML 1.0 forbidden code points; the XML 1.0 specification's character class applies to the whole document, including CDATA contents.

The fix introduces an isValidXml10(int codePoint) predicate matching the XML 1.0 fifth-edition character production, replaces invalid code points with the Unicode replacement character U+FFFD everywhere Transform writes to the buffer, switches both helpers to iterate by code point (so supplementary characters like emoji and overflow CJK survive intact while unpaired surrogates are sanitized), and adds entity-escaping for ' (&#39;) so attribute values delimited with single quotes are safe:

private static final char REPLACEMENT_CHAR = '�';

public static String escapeHtmlTags(final String input) {
    if (Strings.isEmpty(input)) {
        return input;
    }
    final int length = input.length();
    for (int i = 0; i < length; ) {
        final int cp = input.codePointAt(i);
        if (!isValidXml10(cp) || isHtmlTagCharacter(cp)) {
            final StringBuilder out = new StringBuilder(length);
            out.append(input, 0, i);
            appendEscapingHtmlTags(input, i, length, out);
            return out.toString();
        }
        i += Character.charCount(cp);
    }
    return input;
}

private static void appendEscapingHtmlTags(final String input, int i, final int length, final StringBuilder buf) {
    while (i < length) {
        final int ch = input.codePointAt(i);
        switch (ch) {
            case '<':  buf.append("&lt;");  break;
            case '>':  buf.append("&gt;");  break;
            case '&':  buf.append("&amp;"); break;
            case '"':  buf.append("&quot;"); break;
            case '\'': buf.append("&#39;"); break;
            default:
                buf.appendCodePoint(isValidXml10(ch) ? ch : REPLACEMENT_CHAR);
                break;
        }
        i += Character.charCount(ch);
    }
}

private static boolean isValidXml10(final int codePoint) {
    return (codePoint >= ' ' && codePoint < Character.MIN_SURROGATE)
            || codePoint == '\t'
            || codePoint == '\n'
            || codePoint == '\r'
            || (codePoint > Character.MAX_SURROGATE && codePoint <= 0xFFFD)
            || codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT;
}

appendEscapingCData is rewritten to call a new appendSanitizedXml10(...) on every chunk of payload it copies into the buffer, so CDATA bodies receive the same sanitization. A new Log4j1XmlLayoutTest#testWithInvalidXmlCharacters regression case constructs a payload "<>'\"&A\uD800B\uDE00C ￾￿" and asserts that the output replaces every disallowed code point with U+FFFD while still entity-escaping <, >, ', ", and &. A new parameterized TransformTest covers Transform.escapeHtmlTags and Transform.appendEscapingCData directly with control characters, lone surrogates, U+FFFE / U+FFFF, whitespace, and supplementary-plane emoji.

The Log4j1XmlLayout class itself was added in commit 8e01bde35d ("Ported Log4j 1's XMLLayout") on 2016-08-14 and first released in Apache Log4j 2.7 (advisory's lower bound is correct). The two underlying buggy Transform methods are older: escapeHtmlTags was introduced in 2011 and appendEscapingCData in 2014, and both have carried the same un-sanitizing copy semantics throughout. The sibling class org.apache.logging.log4j.core.layout.XmlLayout (in log4j-core) shares the same defect and is addressed by the separately-tracked CVE-2026-34480.

Mitigation

Only recent versions of Apache Log4j 2 receive community support and updates. Older versions have no publicly available fixes for this vulnerability.

The Log4j 1-to-Log4j 2 bridge is deprecated and will not be present in Log4j 3. Users still using the bridge are encouraged to consult the Log4j 1 to Log4j 2 migration guide and specifically the section on eliminating reliance on the bridge.

Users of the affected components should apply one of the following mitigations:

  • Upgrade to a currently supported version of Apache Log4j 2. The OSS fix ships in Apache Log4j 2.25.4 and later.
  • Switch the bridge layout away from Log4j1XmlLayout (or org.apache.log4j.xml.XMLLayout under the Log4j 1 configuration compatibility layer) to a layout that performs proper output encoding, such as JsonTemplateLayout or PatternLayout.
  • Sanitize attacker-influenced input at the application boundary before it can reach a logger call, stripping XML 1.0 forbidden code points from request headers, query strings, and other untrusted text.
  • Leverage a commercial support partner like HeroDevs for post-EOL security support through Never-Ending Support (NES) for Apache Log4j 2.

Credits

  • Ap4sh (Samy Medjahed) (finder)
  • Ethicxz (Eliott Laurie) (finder)
  • jabaltarik1 (independent finder)
  • Piotr P. Karwasz (ppkarwasz) (fixer)
Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2026-34479
PROJECT Affected
Apache Log4j 2
Versions Affected
>=2.7 <=2.25.3, >=3.0.0-beta1 <=3.0.0-beta2
NES Versions Affected
Published date
May 5, 2026
≈ Fix date
March 25, 2026
Category
Denial of Service
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for Apache Log4j
Rss feed icon
Subscribe via RSS
or

By clicking “submit” I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.