Skip to content

RoutingAppender can materialize unbounded number of routes, leading to File Descriptor exhaustion #4181

Description

@h4xr

Description

Currently RoutingAppender based on its configuration can materialize an unbounded number of routes. This coupled with a user controlled or high cardinality key can result in File descriptor exhaustion.

Example configuration which can be problematic:

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="WARN">

    <Appenders>

        <Routing name="Routing">

            <Routes pattern="${ctx:userId}">

                <Route>

                    <File name="File-${ctx:userId}" fileName="logs/user-${ctx:userId}.log">

                        <PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/>

                    </File>

                </Route>

            </Routes>

            <IdlePurgePolicy timeToLive="10" cleanupIntervalMillis="1000"/>

        </Routing>

        <Console name="Console" target="SYSTEM_OUT">

            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

        </Console>

    </Appenders>

    <Loggers>

        <Root level="info">

            <AppenderRef ref="Routing"/>

            <AppenderRef ref="Console"/>

        </Root>

    </Loggers>

</Configuration>

Configuration

Version: 2.26.3

Operating system: Mac OS 15

JDK: openjdk64-25.0.3

Logs

N/A

Reproduction

log4j config:

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="WARN">

    <Appenders>

        <Routing name="Routing">

            <Routes pattern="${ctx:userId}">

                <Route>

                    <File name="File-${ctx:userId}" fileName="logs/user-${ctx:userId}.log">

                        <PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/>

                    </File>

                </Route>

            </Routes>

            <IdlePurgePolicy timeToLive="10" cleanupIntervalMillis="1000"/>

        </Routing>

        <Console name="Console" target="SYSTEM_OUT">

            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

        </Console>

    </Appenders>

    <Loggers>

        <Root level="info">

            <AppenderRef ref="Routing"/>

            <AppenderRef ref="Console"/>

        </Root>

    </Loggers>

</Configuration>

Java Code to Trigger the bug:

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

import org.apache.logging.log4j.ThreadContext;

import java.util.UUID;


public class Harness {

    private static final Logger logger = LogManager.getLogger(Harness.class);


    public static void main(String[] args) {

        System.out.println("Starting DoS harness...");

        for (int i = 0; i < 1000000; i++) {

            String userId = UUID.randomUUID().toString();

            ThreadContext.put("userId", userId);

            [logger.info](http://logger.info/)("Log message for user: " + userId);

            if (i % 10000 == 0) {

                System.out.println("Logged " + i + " unique users...");

            }

        }

        System.out.println("Finished logging.");

    }

}

Detected using Decypher

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    To triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions