If you manage a Log4j Maven dependency, the version that matters is log4j-core — and you want it at 2.17.1 or newer, because that release fully remediates the Log4Shell family of vulnerabilities. Only the log4j-core JAR carries the flaw; applications that use log4j-api alone, without log4j-core on the classpath, are not affected by CVE-2021-44228.
Log4Shell (CVE-2021-44228) is a critical remote code execution vulnerability in Apache Log4j 2.0 through 2.14.1. It works by tricking the application into logging a message that contains a JNDI lookup, which Log4j then resolves — pulling and executing attacker-controlled code. Because Log4j is one of the most widely embedded Java logging libraries, the dependency is often present transitively in projects that never declared it directly.
Finding the Log4j dependency in your Maven tree
The first job is figuring out whether you have log4j-core at all, and at what version. Direct declarations in pom.xml are the easy case; the dangerous case is a transitive pull through some other library. Ask Maven to print the tree filtered to Log4j:
mvn dependency:tree -Dincludes=org.apache.logging.log4j:log4j-core
If that prints nothing, log4j-core is not on your compile or runtime classpath and this specific CVE does not apply. If it prints a version below 2.17.1, you have work to do. To see the whole picture including which parent dependency drags it in, drop the filter:
mvn dependency:tree | grep -i log4j
Pay attention to the distinction between log4j-api and log4j-core. Seeing only log4j-api is the safe outcome for Log4Shell — the vulnerable JNDI lookup code lives in log4j-core.
Why 2.17.1 is the target, not 2.15.0 or 2.16.0
The patch history is a cautionary tale about stopping too early. The fix came in four successive releases — 2.15.0, then 2.16.0, then 2.17.0, then 2.17.1 — because each of the first three left a related weakness that a follow-on advisory addressed (CVE-2021-45046 and CVE-2021-45105 among them). Targeting 2.17.1 for Java 8+ environments gets you past all of them in one move.
Do not settle for 2.15.0 just because it "fixed Log4Shell." It did address the original RCE, but later advisories showed it was incomplete. 2.17.1 is the clean minimum.
Updating and pinning the dependency
If you declare log4j-core directly, set the version explicitly:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
The harder case is a transitive dependency you do not control. Overriding a transitive version by adding a direct dependency works, but the cleaner approach is dependencyManagement, which forces the resolved version everywhere it appears in the graph without you declaring a runtime dependency you do not otherwise want:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
</dependencies>
</dependencyManagement>
Pin both log4j-core and log4j-api to the same version to avoid a mismatch, since they are meant to move together. After the change, re-run mvn dependency:tree and confirm the resolved version is what you pinned — Maven's "nearest wins" resolution can surprise you, and dependencyManagement is how you make it deterministic.
Verifying the fix actually took
Two checks close the loop. First, confirm the resolved version in the tree, not just the version you typed:
mvn dependency:tree -Dincludes=org.apache.logging.log4j:log4j-core
Second, inspect the built artifact. If you produce a fat/uber JAR, unpack it and confirm the bundled Log4j classes come from the patched line, because a shaded dependency can carry an old copy that the source tree no longer shows.
Keeping it fixed
Log4Shell is patched, but the underlying failure mode — an old, transitive dependency lurking in the graph — is permanent. A few habits keep it from recurring:
- Run dependency scanning in CI so a vulnerable
log4j-corefails the build rather than shipping. An SCA tool resolves the full transitive tree and flags the vulnerable version even when yourpom.xmlnever names it. - Use
dependencyManagement(or a BOM) as the single source of truth for versions of libraries you care about. - Periodically audit fat JARs, since shaded copies hide from source-level checks.
The same discipline applies to any high-blast-radius library. If you want the broader picture of scanning Java projects for known-vulnerable dependencies, the Java vulnerability scanning workflow covers the tooling.
FAQ
What Log4j version should my Maven dependency use?
Target log4j-core 2.17.1 or later for Java 8+ environments. It remediates the full Log4Shell family (CVE-2021-44228, CVE-2021-45046, CVE-2021-45105) that earlier patches only partly addressed.
I only see log4j-api, not log4j-core. Am I safe from Log4Shell?
For CVE-2021-44228, yes — the vulnerable JNDI lookup code is in log4j-core. Applications using only log4j-api without log4j-core on the classpath are not affected.
How do I fix a transitive log4j-core dependency?
Add a dependencyManagement entry pinning log4j-core (and log4j-api) to 2.17.1. That forces the resolved version across the whole graph without adding an unwanted direct dependency. Re-run mvn dependency:tree to confirm.
Is 2.15.0 good enough?
No. 2.15.0 fixed the original RCE but left related issues addressed only in 2.16.0, 2.17.0, and finally 2.17.1. Go straight to 2.17.1.