December 14, 2021·4 min read·engineeringkafkasecurityloggingconfiguration

Kafka's Log4j 1.x exposure depends on JMSAppender configuration

The Log4j 1.x JMSAppender advisory describes a configuration-dependent code execution risk. Kafka operators need to distinguish the shipped logging library from the appenders and configuration actually used in a deployment.

A logging library being present and a vulnerable logging path being configured are different facts. The Apache disclosure dated December 13 describes CVE-2021-4104 in Log4j 1.2's JMSAppender. Exploitation requires the relevant appender configuration and attacker control over its configuration values. It is a separate issue from treating ordinary logged text as sufficient to trigger the Log4j 2 vulnerability.

Kafka's security guidance for this issue identifies Log4j 1.2.17 in components including the broker and Connect. It describes the risk where JMSAppender is configured and the attacker can modify its binding properties. That conditional statement should remain intact when a dependency scanner identifies the library in an installation.

I regard the effective configuration as part of the system being operated. A retained event log can serve several applications, while the broker's own logging system has a different purpose and set of outputs. Understanding those outputs requires reading the deployed logging configuration, rather than inferring it from a JAR filename.

The appender determines where logging sends work

The Apache advisory names TopicBindingName and TopicConnectionFactoryBindingName. An attacker able to supply those values can cause JMSAppender to perform JNDI requests that lead to remote code execution. It says this is not the default Log4j 1.2 configuration. The security boundary includes who can change the logging setup, alongside which classes are available to it.

This is why a broad statement that every Kafka installation exposes the same remote logging attack would be inaccurate. The disclosed precondition concerns configuration access and the JMS-based output path. Conversely, finding that a default file does not use that path is evidence about that configuration, not proof that every plugin and customized distribution has the same contents.

The advisory also notes that Log4j 1.2 reached end of life in August 2015. That gives the dependency a wider maintenance context, but it does not remove the need to analyze this particular issue according to its actual conditions. A general concern about an old dependency and a demonstrated reachable path are different assessments.

Kafka's supplied configuration names other outputs

The logging configuration at the Kafka 3.0.0 tag configures a root logger using console and rolling-file appenders. Console output uses a pattern layout. The main rolling-file appender writes server.log beneath the configured Kafka logs directory.

Other appenders create dedicated files for controller activity, state changes and the log cleaner. Request logging has its own appender and a warning-level configuration in the supplied file. The file also defines authorizer logging separately. These named outputs show what the distribution's example enables, without assuming that the same file remains unchanged in a deployed environment.

For example, the supplied console definition uses this class:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

The name stdout is referenced by the root logger. The appender's configured class determines how that output is implemented. Looking at both the logger reference and the class definition is more informative than searching only for a general Log4j dependency.

The configuration also controls additivity for specific loggers. Controller and request loggers have explicit appenders and disable additivity in the supplied file. This matters when tracing an output path, because a message's category and the configuration around it determine which appender receives it.

The authorizer configuration documents access denials at INFO and says DEBUG includes allowed accesses too. That is a choice about which events are recorded. It is distinct from the appender class, which determines where and how selected events are emitted. Changing one does not establish that the other has changed, so both belong in an account of effective logging behavior.

None of these observations describes a JMS output in that file. They establish the distribution's supplied configuration, leaving customized files and plugin dependencies as separate inputs to the deployed system. The conditional vulnerability should be assessed at that same level of specificity.

A Kafka distribution can remove the unused class

The Debezium project's December 14 explanation gives a concrete response within the Kafka ecosystem. Its container images include Log4j 1.2.17 for Kafka-related components, but do not use JMSAppender by default. The project removes the JMSAppender class from its image's JAR as a precaution in Debezium 1.7.2.Final, released today.

That is a statement about those supplied images. The post explicitly distinguishes users running the connectors in other Kafka distributions, where the class may remain. It also distinguishes connector archives and the Debezium Server distribution, which do not contain that JAR. The scope of an artifact change matters when applying the project's announcement to another installation.

Removing an unused implementation and protecting configuration address different parts of the exposure. Removing the class prevents that artifact from supplying its implementation. Restricting writes to the configuration prevents an unauthorized actor from changing logging behavior through that file. Neither observation should be generalized to unrelated classes or arbitrary modifications elsewhere in a deployment.

Configuration integrity remains an operational requirement

Kafka's guidance recommends protecting logging configuration against write access and identifies removing JMSAppender from the artifact as a mitigation where no new Log4j 1.x release is available. Those actions concern the executable contents and the authority to choose how logging uses them. They are more specific than changing the minimum severity level of log messages.

I find the distinction useful because a logging configuration can select behavior with effects outside the process. It deserves the same ownership clarity as the configuration that selects a broker listener or an authentication mechanism. A file that looks like an observability detail can still determine which implementation executes and which remote service it contacts.

The disclosed Kafka exposure is therefore conditional on the configured JMS path and control of its relevant settings. The supplied Kafka logging file and Debezium's artifact changes provide concrete evidence for their respective distributions. A deployment's effective logging file, loaded classes and configuration permissions establish how those facts apply to the processes it actually runs.