October 27, 2026
Understanding and Mitigating Log4Shell CVE-2021–44228
A logging library trusted a lookup hidden inside user input, and defenders had to find every copy of that library. Here is the concept…

By Muhammad Asim Shahzad
7 min read
A logging library trusted a lookup hidden inside user input, and defenders had to find every copy of that library. Here is the concept level chain, the detection signals, and the verified fix.
Cover image: AI generated illustration made in Canva.
Some vulnerabilities live in one product. Log4Shell lived in a library that thousands of products carried inside them. In December 2021, defenders learned that a line of text typed into a login form, a chat box or a search field could make a Java server reach out to an external server and run code from that server. No password was needed. The text only had to be logged.
Disclosure: This article was researched and written with AI assistance, and it was checked for accuracy and originality before publishing.
This article explains the vulnerability in plain words, then explains the attack chain at concept level for a lab you own, and closes with detection, the real fix and how to verify that the fix worked. Everything here concerns a publicly disclosed vulnerability, CVE-2021–44228, and a lab you own. Never run any of this against a system you do not own.
The vulnerability, explained simply
Apache Log4j 2 is a logging library for Java applications. Versions from 2.0-beta9 through 2.14.1 included a feature called message lookups. When Log4j printed a log message, it would look inside the message for special patterns and resolve them. One pattern used JNDI, the Java Naming and Directory Interface, which can fetch objects from network services such as LDAP.
The failure is easy to state. Attacker controlled text reached the logger. The logger saw a JNDI pattern inside that text and obeyed it, connecting to an LDAP server the attacker controlled. That server answered with a reference to a Java class hosted on an attacker web server. The victim application downloaded the class and executed it with the full rights of the application process. Logging, a feature meant to record events, became a remote control.
Public references for study: government guidance on this vulnerability is public at https://www.cftc.gov/media/6886/MPDCyberAlert121421/download and a detailed public analysis of the fix history is at https://raven.io/blog/log4j-cve-history
Lab setup
Build this only on an isolated host only network with no internet route for the victim machine beyond the lab, and snapshot every virtual machine before you begin so you can roll back.
-
Victim machine: a virtual machine running a deliberately vulnerable Java application that uses Log4j 2.14.1. Public training images built for this CVE exist for exactly this purpose. Give it a lab address such as 10.10.0.20.
-
Attacker machine: a Linux virtual machine on the same host only network, for example 10.10.0.10, with a Java development kit, a simple web server and a JNDI LDAP server tool built for Log4Shell training labs.
-
Safety rules for the lab: no port forwarding, no bridged networking, no real credentials anywhere in the lab, and full disk snapshots before the first run.
The Log4Shell Chain: logged input triggers a JNDI lookup, the attacker LDAP server answers, and code is downloaded and run. This image is an AI generated illustration made in Canva.
The attack chain, at concept level
The chain has four links, and breaking any one of them stops it.
First, untrusted input reaches the logger. The precondition is simple and is also the first test a defender should run in a lab: does a harmless unique word sent through a field the application accepts appear in the application log? If it does, the input reaches Log4j.
Second, the logger resolves a lookup inside that input. In a lab, a safe callback test proves this link without any harmful effect: a lookup that points only at a listener you control inside the lab, which records the connection and serves nothing harmful. A connection arriving at your listener proves the lookup fires. In a real assessment this callback proof is where responsible testing stops.
Third, the external reference is followed. The lookup answer points the application to a second server, which supplies a Java class. The application downloads that class because the lookup mechanism was designed to fetch remote objects, with no check that the object was safe or expected.
Fourth, the class runs inside the application process. That is the impact link. Code execution at the privilege level of the Java application, which in many real deployments meant full server control, follows from the three links above, not from any separate flaw.
Defenders should read the chain backwards. If untrusted input never reaches the logger in raw form, if lookups are disabled, if outbound connections from the application server are blocked, or if the library is patched, the chain breaks.
What the attacker gains
Unauthenticated remote code execution is the highest impact class in security, and Log4Shell added two multipliers. The vulnerable code sat in a library, so one pattern attacked countless products at once. And the trigger was any logged input, so the attack surface was every form, header and field an application recorded. Defenders could not fix one app. They had to find every copy of one library, including copies hidden inside other products.
How defenders detect it
-
Hunt the logs. Search application and web logs for the jndi pattern and its obfuscated cousins, including nested lookups and mixed case tricks that attackers used to slip past simple filters.
-
Watch the network. A Java application server that suddenly opens outbound LDAP or HTTP connections to unknown addresses is showing the exact behaviour this exploit needs.
-
Scan the estate properly. Inventory every application and appliance for Log4j core files at vulnerable versions, including libraries bundled inside vendor products. Public CISA guidance during the incident centred on this inventory problem.
-
Deploy detection rules. Public rule sets for web application firewalls and intrusion detection covered the lookup patterns, and endpoint tools flagged Java processes spawning shells or writing unexpected files.
Remediation & Defensive Controls
Fix and Verify: upgrade to 2.17.1 or later, remove JndiLookup if stuck, retest the callback, and rescan for hidden copies. This image is an AI generated illustration made in Canva.
For defenders reviewing a Log4Shell report, the test checklist is short. Confirm the deployed jar version on disk, not only in a spreadsheet. Repeat the lab callback test against the patched build and confirm no connection reaches your listener. Rescan the estate for nested copies inside other applications, including vendor bundled copies. Keep the log hunts running for a period after patching, because exploitation attempts against this CVE continued for years. Defenders should also log lookup patterns and outbound connection attempts from Java application servers, and alert when a Java process opens an outbound LDAP or HTTP connection to an unknown address or spawns a shell or writes an unexpected file.
The definitive fix is to upgrade Log4j 2 to a safe release. Public guidance settled on version 2.17.1 or later for Java 8, with 2.12.4 for the Java 7 branch line in the 2.12 series and later safe releases beyond those numbers. Follow on issues CVE-2021–45046, CVE-2021–45105 and CVE-2021–44832 are the reason teams should land on the later releases rather than the first emergency patch.
Temporary measures from public vendor guidance, useful only while an upgrade is scheduled: set the system property log4j2.formatMsgNoLookups to true for versions from 2.10 onward, or remove the JndiLookup class from the log4j core jar file.
The core fix, shown here as sanitized logic with no real account data and no working payload:
Vulnerable logic: untrusted input logged with lookups enabled
logger.info(user_input)
Patched logic: upgrade to a safe Log4j release, and log untrusted input with lookups disabled
logger.info("Received request from {}", sanitized_user_id)
Vulnerable logic: untrusted input logged with lookups enabled
logger.info(user_input)
Patched logic: upgrade to a safe Log4j release, and log untrusted input with lookups disabled
logger.info("Received request from {}", sanitized_user_id)
For builders, the durable fixes are well known.
-
Upgrade every copy of Log4j, including copies bundled inside vendor products, to a safe release.
-
Disable message lookups where the feature is not needed, and treat any lookup that reaches an external server as a design fault.
-
Block outbound LDAP and HTTP connections from application servers at the network level, so a missed library copy has less room to call out.
-
Keep an accurate software inventory, so a library flaw can be found across the estate in hours, not weeks.
-
Retest the fix with the lab callback test, rescan for nested copies, and keep detection rules live after patching.
Verify the fix like an attacker and an auditor together. Confirm the deployed jar version on disk, not only in a spreadsheet. Repeat the lab callback test against the patched build and confirm no connection reaches your listener. Rescan the estate for nested copies inside other applications. Keep the log hunts running for a period after patching, because exploitation attempts against this CVE continued for years.
Closing takeaways
Log4Shell is the supply chain lesson of the decade. A feature nobody asked for, inside a library nobody reviewed, turned routine logging into remote code execution across the world.
For testers, the craft lesson is the callback proof. One recorded connection from your own lab listener proves the flaw completely. For builders, the lesson is inventory. You cannot patch a library you do not know you run.
I write from more than thirteen years in offensive security, including HackerOne Top 100 recognition in 2014 to 2016, Synack Red Team work and leading application security and VAPT at bank scale today as SVP Head Application Security and VAPT at UBL. Log4Shell week is the incident I cite whenever a team calls patching a routine chore.
Disclaimer: This article is written strictly for educational awareness, defensive security research, and authorized Vulnerability Assessment and Penetration Testing (VAPT) purposes. All endpoints and identifiers have been redacted and anonymized.
Sources credited in this article: CISA Apache Log4j vulnerability guidance as republished by a public regulator, the public Log4j CVE history analysis, and a public analysis of the Log4Shell version history. All research is based on publicly disclosed material only, and all exploitation discussion describes an isolated lab only, at concept level.
Tags: Cybersecurity, Application Security, Penetration Testing, Web Security, Infosec
Written by Muhammad Asim Shahzad, SVP Head Application Security and VAPT at UBL, with thirteen plus years in offensive security, HackerOne Top 100 history, Synack Red Team experience and CVE-2021–31521 to his name. More writing and services at protector47.com. Connect with Asim on LinkedIn under the name protector47 and find his public researcher history through HackerOne under the name protector47.