CVE-2025-68161
Overview
Apache Log4j 2 is a widely deployed Java logging framework, used directly and as a transitive dependency in most JVM application stacks. The framework ships a family of network appenders (SocketAppender, SyslogAppender, SmtpAppender) that can wrap their TCP transport in TLS via a nested <Ssl> configuration element so that log records leave the application encrypted and authenticated.
A medium-severity vulnerability (CVE-2025-68161, classified as CWE-297 Improper Validation of Certificate with Host Mismatch) has been identified in SslSocketManager, the class that backs every TLS-wrapped socket appender. When the manager opens an SSLSocket to the configured log receiver, it never sets SSLParameters.setEndpointIdentificationAlgorithm("HTTPS"), never consults sslConfiguration.isVerifyHostName(), and never forces an early handshake. The JSSE engine therefore validates the certificate chain against the configured trust store but never compares the server certificate's CN/SAN against the configured peer host. Any certificate signed by a CA in that trust store, for any host, is accepted. The verifyHostName configuration attribute (introduced in 2.12.0) and the log4j2.sslVerifyHostName system property were both silently no-ops. A network-positioned attacker who can intercept or redirect traffic between the logging client and the receiver, and who can present a certificate signed by a trusted CA (the default JRE trust store ships dozens), can transparently impersonate the log receiver and capture or forge the entire log stream.
Per OWASP: "A man-in-the-middle (MITM) attack is a general term for when a perpetrator positions himself in a conversation between a user and an application, either to eavesdrop or to impersonate one of the parties." Skipping hostname verification on a TLS handshake is the canonical enabler for this class of attack, because trust-store cert chain validation alone proves only that *some* CA-signed certificate was presented, not that the certificate was issued for the host the application intended to talk to.
The CVSS v4.0 base score is 6.3 (Medium) with vector CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:L/SA:N; under CVSS v3.1, NVD scores the vulnerability 4.8 with vector AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N. Attack complexity is high because the attacker must already be able to position themselves on the network path between the logging client and the receiver and must hold a CA-trusted certificate. No authentication and no user interaction are required. Impact is bounded to confidentiality and integrity of the captured log stream, plus a low subsequent-system integrity impact when forged log records reach a SIEM or audit pipeline.
This issue affects Apache Log4j 2 versions 2.0-beta9 through 2.25.2, and pre-release versions 3.0.0-alpha1 through 3.0.0-beta3.
Details
Module Info
- Product: Apache Log4j 2
- Affected packages: log4j-core
- Affected versions: >=2.0-beta9 <=2.25.2, >=3.0.0-alpha1 <=3.0.0-beta3
- GitHub repository: https://github.com/apache/logging-log4j2
- Published packages: https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-core
- Package manager: Maven
- Fixed in:
- NES for Apache Log4j 2 2.17.x
- OSS Apache Log4j 2 2.25.3
Vulnerability Info
The vulnerability is in org.apache.logging.log4j.core.net.SslSocketManager (formerly TLSSocketManager), specifically the createSocket helper that opens TLS connections for the Socket, Syslog, and SMTP appenders.
An application is vulnerable when all of the following are true:
- The application uses Apache Log4j 2 between 2.0-beta9 and 2.25.2 inclusive (or a 3.x pre-release in the affected range)
- The application configures a TLS-wrapped network appender (SocketAppender, SyslogAppender, or SmtpAppender) with a nested <Ssl> element, or sets the log4j2.sslVerifyHostName system property expecting hostname verification
- A network attacker can position themselves between the application and the log receiver and can present a server certificate signed by any CA in the appender's trust store (the default JRE trust store contains many CAs)
When those conditions are met, the manager's createSocket method opens an SSLSocket, applies socket options, calls connect(...), and returns. No SSLParameters are configured and the handshake is left to be triggered lazily by the first read or write, by which point the connection is already established to whatever endpoint answered the TCP request.
Prior to the fix, SslSocketManager.createSocket looked like this (pre-fix code from the commit that immediately precedes the patch):
@Override
protected Socket createSocket(final InetSocketAddress socketAddress) throws IOException {
final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfig);
final Socket newSocket = socketFactory.createSocket();
newSocket.connect(socketAddress, getConnectTimeoutMillis());
return newSocket;
}
static Socket createSocket(
final InetSocketAddress socketAddress,
final int connectTimeoutMillis,
final SslConfiguration sslConfiguration,
final SocketOptions socketOptions)
throws IOException {
final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfiguration);
final SSLSocket socket = (SSLSocket) socketFactory.createSocket();
if (socketOptions != null) {
socketOptions.apply(socket);
}
socket.connect(socketAddress, connectTimeoutMillis);
if (socketOptions != null) {
socketOptions.apply(socket);
}
return socket;
}
There is no call to setEndpointIdentificationAlgorithm("HTTPS"), no SSLParameters configuration, no SNI population, no inspection of sslConfiguration.isVerifyHostName(), and no eager startHandshake(). The lazy handshake at first I/O therefore performs only RFC 5280 chain validation against the trust store; it never compares the server certificate's identity to the configured peer host.
The fix rewrites createSocket so that the configured host name is threaded down into the helper, hostname verification is gated on sslConfiguration.isVerifyHostName(), SSLParameters.setEndpointIdentificationAlgorithm("HTTPS") is invoked so the JSSE engine performs RFC 6125 hostname matching during the handshake, an SNI server name is populated where applicable, and socket.startHandshake() is called eagerly so any verification failure surfaces before the first log event is written:
@Override
protected Socket createSocket(final InetSocketAddress socketAddress) throws IOException {
return createSocket(getHost(), socketAddress, getConnectTimeoutMillis(), sslConfig, getSocketOptions());
}
private static Socket createSocket(
final String hostName,
final InetSocketAddress socketAddress,
final int connectTimeoutMillis,
final SslConfiguration sslConfiguration,
final SocketOptions socketOptions)
throws IOException {
final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfiguration);
final SSLSocket socket = (SSLSocket) socketFactory.createSocket();
if (socketOptions != null) {
socketOptions.apply(socket);
}
socket.connect(socketAddress, connectTimeoutMillis);
if (sslConfiguration.isVerifyHostName()) {
final SSLParameters sslParameters = socket.getSSLParameters();
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
final SNIHostName serverName = createSniHostName(hostName);
if (serverName != null) {
sslParameters.setServerNames(Collections.singletonList(serverName));
}
socket.setSSLParameters(sslParameters);
}
socket.startHandshake();
return socket;
}
A new createSniHostName(String) helper guards against IP literals (RFC 6066 forbids them in SNI HostName) and gracefully handles values that SNIHostName::new rejects. The fix also tightens nullability of SslConfiguration.loadKeyManagers and loadTrustManagers so the JSSE default key/trust managers are used when none are configured.
The defect is as old as the SSL/TLS appender itself. The vulnerable createSocket shape was introduced in commit c4829556d ("LOG4J2-338: Add TLSAppender") on 2013-09-05 (first as TLSSocketManager, then renamed to SslSocketManager in May 2014) and was first released to the public in Apache Log4j 2.0-beta9. The verifyHostName attribute and the log4j2.sslVerifyHostName system property were added in 2.12.0 but were never wired into SslSocketManager, so the attribute path remained a no-op until 2.25.3 and only the system-property path was honored from that release. The follow-up CVE-2026-34477 closes the remaining <Ssl verifyHostName="true"> attribute path in 2.25.4.
Mitigation
Only recent versions of Apache Log4j 2 receive community support and updates. Older versions have no publicly available fixes for this vulnerability.
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.3 and later.
- Restrict the trust store configured for the Socket, Syslog, or SMTP appender to contain only the CA certificates required for the intended log-receiver communication scope, following NIST SP 800-52 Rev. 2 §4.5.2. This narrows the set of certificates an attacker could obtain to impersonate the receiver but does not eliminate the underlying defect.
- Where feasible, replace the Socket appender with the HTTP appender (which uses a separate code path that already verifies host names) or front the receiver with mutual TLS so client and server cross-authenticate.
- Leverage a commercial support partner like HeroDevs for post-EOL security support through Never-Ending Support (NES) for Apache Log4j 2.
Credits
- Samuli Leinonen (finder), reported through the Log4j Bug Bounty Program on YesWeHack, funded by the Sovereign Tech Agency
- Volkan Yazıcı (vy) (fixer)
- Piotr P. Karwasz (ppkarwasz) (GHSA analyst)