Remediation Guides

Apache Log4j 1.x Multiple Vulnerabilities: How to Migrate to Log4j 2

26 September 2026 9 min read

The Log4j 1.x vulnerabilities finding means a Log4j 1.x jar (usually log4j-1.2.17.jar) was found on the host. Log4j 1.x reached end of life in 2015 and receives no fixes, so there is no 1.x patch. The fix is to migrate to a current Log4j 2 release, using the log4j-1.2-api bridge where code still calls the 1.x API.

What the scanner is actually detecting

Nessus reports this condition under up to three plugins, all in the Misc. family and all local (credentialed) checks for Windows, macOS and Unix:

Plugin ID Title Notes
156860 Apache Log4j 1.x Multiple Vulnerabilities Lists CVE-2019-17571, CVE-2020-9488, CVE-2022-23302, CVE-2022-23305, CVE-2022-23307 and CVE-2023-26464
182252 Apache Log4j SEoL (<= 1.x) Unsupported software check, no CVEs, scored as critical
156032 Apache Log4j Unsupported Version Detection (deprecated) Retired; Tenable points users to the SEoL plugins instead

Tenable’s plugin text says the result is based on the self-reported version number of the installation. Both active plugins depend on the installed_sw/Apache Log4j inventory item, which comes from the Log4j detection plugins “Apache Log4j Installed (Linux / Unix)” and “Apache Log4j JAR Detection (Windows)”. The Windows detection needs PowerShell 5 or later, and with Perform thorough tests enabled it also reads the manifest and properties files inside each Java archive. In short, the scanner found a jar on disk. It did not test whether an application is exploitable.

Real-world risk

This is not Log4Shell. The Apache security page states that Log4j 1 has no Lookups, so CVE-2021-44228 does not apply the same way. Most 1.x CVEs need a non-default component to be in use:

  • CVE-2019-17571: SocketServer deserializes untrusted data. It becomes remote code execution only when the server listens to untrusted network traffic and a gadget chain is on the classpath.
  • CVE-2022-23305: JDBCAppender builds SQL from logged values, so text an attacker gets into the logs can run as SQL. This only applies when JDBCAppender is configured, and it is probably the most realistic remote path.
  • CVE-2022-23302 and CVE-2021-4104: JMSSink and JMSAppender perform JNDI lookups. Exploiting them needs write access to the Log4j configuration (or, for JMSSink, an LDAP service the attacker controls).
  • CVE-2022-23307: a deserialization flaw in the bundled Chainsaw log viewer.
  • CVE-2023-26464: a memory exhaustion (denial of service) issue in Chainsaw and SocketAppender, and only on JRE versions older than 1.7.

The long-term risk is that Apache stopped checking reports against Log4j 1 in August 2015. Any flaw found later stays unfixed. The CVSS 10.0 on plugin 182252 is Tenable’s standard score for unsupported software. It is not a measured exploitability score for your application.

How to confirm it on the host

On Linux, find the jars and read their versions:

find / ( -path /proc -o -path /sys ) -prune -o -type f -iname 'log4j*.jar' -print 2>/dev/null
unzip -p /opt/app/lib/log4j-1.2.17.jar META-INF/MANIFEST.MF | grep -i version

Jars packed inside WAR, EAR or fat jars do not show up in a file name search. List the contents of each archive:

find / ( -path /proc -o -path /sys ) -prune -o -type f ( -name '*.war' -o -name '*.ear' -o -name '*.jar' ) -print 2>/dev/null |
  while read -r f; do unzip -l "$f" 2>/dev/null | grep -Eiq 'log4j-1.[0-9]+.[0-9]+.jar' && echo "$f"; done

To check whether a running JVM actually has the jar loaded, run lsof -nP | grep -Ei 'log4j-1.[0-9]+.[0-9]+.jar'.

On Windows, search each drive and inspect a hit with the .NET zip classes:

Get-ChildItem -Path C: -Filter 'log4j*.jar' -Recurse -File -Force -ErrorAction SilentlyContinue | Select-Object FullName, LastWriteTime

Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead('C:Appliblog4j-1.2.17.jar')
(New-Object System.IO.StreamReader($zip.GetEntry('META-INF/MANIFEST.MF').Open())).ReadToEnd()
$zip.Entries | Where-Object { $_.FullName -match 'JMSAppender|JMSSink|JDBCAppender|SocketServer|chainsaw/' } | Select-Object FullName
$zip.Dispose()

If the software is your own, check the build as well. Dependency scanning is the SCA part of the differences between SAST, DAST and SCA, and it will catch the jar before it reaches a server:

mvn dependency:tree -Dincludes=log4j:log4j
gradle dependencyInsight --dependency log4j:log4j --configuration runtimeClasspath

How to fix it

Applications you build: migrate to Log4j 2

The permanent fix is to move your code to the Log4j 2 API and use log4j-core as the backend. The Apache migration guide notes that the Log4j1ToLog4j2 OpenRewrite recipe can do much of the code conversion automatically. If a transitive dependency pulls in 1.x, exclude it:

<exclusions>
  <exclusion>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
  </exclusion>
</exclusions>

Code that still calls the 1.x API: the log4j-1.2-api bridge

If rewriting every logging call is not realistic right now, replace the 1.x jar with the bridge. The bridge provides the org.apache.log4j classes on top of Log4j 2. Remove log4j:log4j, ch.qos.reload4j:reload4j and org.slf4j:log4j-over-slf4j from the runtime classpath first, because Apache lists all three as incompatible with the bridge. Then add:

<properties>
  <log4j2.version>2.26.1</log4j2.version>
</properties>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-1.2-api</artifactId>
  <version>${log4j2.version}</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>${log4j2.version}</version>
</dependency>

Version 2.26.1 was the current release on the Log4j download page at the time of writing, so check that page before you pin a version. Keep the bridge, log4j-api and log4j-core on the same version. The bridge has had security fixes of its own in 2.x releases.

To keep an existing log4j.properties or log4j.xml, start the JVM with -Dlog4j1.compatibility=true (or set LOG4J_COMPATIBILITY=true). A better option is to convert the file once, with log4j-api, log4j-core and log4j-1.2-api on the CLASSPATH:

java org.apache.log4j.config.Log4j1ConfigurationConverter --in log4j.properties --out log4j2.xml

Apache says the bridge “is not conceived as a long term solution”, so treat it as a stepping stone.

Vendor products that bundle log4j-1.2.17.jar

If the jar ships inside a commercial or open source product, ask the vendor for a release that no longer includes Log4j 1.x. Swapping in the bridge jars yourself can work, but it may leave you on an unsupported configuration. Test it on a non-production copy and get the vendor’s agreement first.

Interim hardening (does not clear the finding)

Red Hat’s CVE pages describe removing the dangerous classes from the jar. Put a backup in an archive outside the application tree first:

tar czf /root/log4j1-rollback.tgz /opt/app/lib/log4j-1.2.17.jar
zip -q -d /opt/app/lib/log4j-1.2.17.jar org/apache/log4j/net/JMSAppender.class
zip -q -d /opt/app/lib/log4j-1.2.17.jar org/apache/log4j/net/JMSSink.class
zip -q -d /opt/app/lib/log4j-1.2.17.jar org/apache/log4j/jdbc/JDBCAppender.class
zip -q -d /opt/app/lib/log4j-1.2.17.jar org/apache/log4j/net/SocketServer.class
zip -q -d /opt/app/lib/log4j-1.2.17.jar org/apache/log4j/net/SimpleSocketServer.class
zip -q -d /opt/app/lib/log4j-1.2.17.jar 'org/apache/log4j/chainsaw/*'

This shrinks the attack surface, but the version string inside the jar does not change, so plugins 156860 and 182252 will keep firing. Record it as a compensating control with an expiry date, not as a fix.

How to verify the fix and rescan

  1. Restart the application, then run the find or Get-ChildItem search again. Only log4j-api, log4j-core and (if used) log4j-1.2-api 2.x jars should remain.
  2. Confirm the application writes logs to the expected appenders after the restart.
  3. Run a credentialed Nessus scan with the same policy. With the 1.x jar gone, 156860 and 182252 should no longer report for that host. If 156032 still appears, it comes from older scan data, because that plugin is deprecated.

What can break and how to roll back

  • Old JVMs: the Log4j download page lists 2.12.x as the last release line that supports Java 7. An application stuck on Java 7 or older needs a JVM upgrade before it can use a current 2.x release.
  • Unsupported components: the bridge natively supports a fixed list of appenders, filters and layouts, including ConsoleAppender, FileAppender, RollingFileAppender, SocketAppender and SyslogAppender. Configurations that use JDBCAppender, JMSAppender, SMTPAppender or custom appenders must be rewritten as Log4j 2 components, or logging to those targets stops.
  • Config interpolation: the migration guide says ${foo} references become ${sys:foo} in Log4j 2 configurations.

To roll back, restore the original jar and configuration from your archive, remove the 2.x jars you added, and restart the service. For the interim hardening, extract the saved jar back over the modified one.

Common false positive reasons

  • Leftover copies: old install folders, .jar backups, and Maven caches such as ~/.m2/repository/log4j/log4j/1.2.17/. The jar is really there, but nothing loads it. Delete it rather than disputing the finding.
  • Bridge confusion: log4j-1.2-api-2.x.jar has “1.2” in its name. If a tool that matches on file names flags it, check the manifest, because the file is Log4j 2 code.
  • Images and layers: a jar removed on the running host can remain in a base image or an older container layer. See container scanner false positives for how layers cause this.
  • Stale results: data collected before the change, or a scan whose credentialed login failed. Rescan before you dispute the finding.

FAQ

Is Log4j 1.2.17 vulnerable to Log4Shell?

Not to CVE-2021-44228 itself, because Log4j 1 has no Lookups. The related CVE-2021-4104 affects 1.2 only when JMSAppender is configured.

Is there a patched Log4j 1.x release?

No. 1.2.17 is the final Apache release, and Apache does not check or fix vulnerabilities reported after August 2015.

Does the log4j-1.2-api bridge clear the finding?

Only once the old log4j-1.2.x jar is gone. The bridge is Log4j 2 code released with 2.x versions. If a rescan still flags it, check the path and version in the plugin output.

Why do I see three plugin IDs for one jar?

156860 covers the CVEs and 182252 covers end of life. 156032 is the deprecated predecessor of the SEoL check.

Tracking this finding across many hosts

Log4j 1.x jars tend to sit inside vendor products on many servers at once, so it helps to track the finding per host. SITEY imports findings from 16 scanners, including Nessus results uploaded as .nessus exports, and merges duplicates within each scanner. It supports per-finding retest for Nessus, so you can confirm closure once the jar is gone.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing