CVE-2021-44228 — Log4Shell
The Log4j 2.x logger interpolated ${jndi:ldap://...} strings
when logging arbitrary content. An attacker who could get a
string into a log statement (almost any user-controlled
field — User-Agent, search query, username) could trigger an
LDAP/RMI lookup, fetch a remote class, and execute it. The
naive fix (upgrade to 2.15.0) had a follow-up CVE because the
fix was incomplete; the durable fix is 2.17.1+ plus class
removal.
Affected versions
- Log4j-core 2.0-beta9 through 2.14.1 — vulnerable.
- Log4j-core 2.15.0 — incomplete fix (CVE-2021-45046).
- Log4j-core 2.16.0 — DoS via uncontrolled recursion (CVE-2021-45105).
- Log4j-core 2.17.0 — JDBC Appender RCE under specific config (CVE-2021-44832).
- Log4j-core 2.17.1+ (or 2.12.4 / 2.3.2 for older Java versions) — the durable fix.
log4j-api alone is not vulnerable; the bug is in
log4j-core’s pattern-substitution code path.
Indicator-of-exposure
Having log4j-core in the classpath is the necessary
condition. Sufficient exposure also requires:
- A vulnerable version (per the above).
- A code path that logs untrusted input. In a typical web application, almost every code path qualifies — request headers, paths, bodies are routinely logged.
If the only logging in the application is a fixed string with no user-controlled fields and no exception traces (rare), exposure may be limited. Don’t rely on that for triage; the attacker’s job is to find one untrusted input that makes it to a log line.
Remediation strategy
The full fix is all of:
- Upgrade
log4j-coreto 2.17.1+ (or 2.12.4 / 2.3.2 on older Java versions). - Set the JVM flag
-Dlog4j2.formatMsgNoLookups=true(or theLOG4J_FORMAT_MSG_NO_LOOKUPS=trueenvironment variable) for defence-in-depth. - Remove
JndiLookup.classfrom any vendored Log4j JAR that cannot be upgraded. - Audit for
log4j-1.x. The 1.x branch has different CVEs (CVE-2019-17571, CVE-2022-23305) and is end-of-life.
Steps 2 and 3 are the mitigation path when the upgrade can’t ship immediately; both are still reasonable defence-in-depth after the upgrade.
The prompt
You are remediating Log4Shell (CVE-2021-44228 / 45046 / 45105
/ 44832) in this repository. Output a PR (or set of PRs, one
per Maven module) or a TRIAGE.md.
## Step 0 — Inventory
1. Locate every `log4j-core` dependency in the dependency
graph: `pom.xml`, `build.gradle`, `build.sbt`, the lockfile
if any, and shaded/uber-JAR contents.
2. Record the current version of each. Note any vendored or
shaded copies.
3. List Log4j 1.x usages separately — they need a different
fix path (replace with reload4j or upgrade to 2.x).
## Step 1 — Apply the upgrade
For each `log4j-core` reference:
1. Bump the version to 2.17.1+ (or 2.12.4 on Java 7, 2.3.2 on
Java 6). Match the major-runtime constraint of the project.
2. Bump `log4j-api` to the same version. Mismatch breaks at
runtime.
3. Run the project's test suite. If tests fail because of
genuinely-changed behaviour (rare in 2.14 → 2.17), document
the change in the PR.
## Step 2 — Defence-in-depth
1. Add `-Dlog4j2.formatMsgNoLookups=true` to the JVM args
in the project's launcher / Dockerfile / deploy
configuration.
2. For any vendored / shaded JAR that cannot be upgraded
immediately, remove `JndiLookup.class` from the JAR:
`zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class`.
3. Verify with `unzip -l log4j-core-*.jar | grep JndiLookup`
showing no entry.
## Step 3 — Verify
1. Re-run the SBOM / SCA scan against the post-upgrade
artifact. CVE-2021-44228, -45046, -45105, and -44832 must
all show as "fixed" or "not present."
2. Run a behaviour test: a log statement that includes
`${jndi:ldap://example.invalid/x}` must log the literal
string, not trigger an LDAP request.
3. Confirm the JVM flag is being applied at runtime by
inspecting `java -XshowSettings:properties` output (or the
container's startup logs).
## Step 4 — Open the PR
- Branch: `remediate/cve-2021-44228-log4shell`.
- Title: `[Security][CVE-2021-44228] upgrade log4j-core to 2.17.1+`.
- Body must include:
- CVE summary and link to the advisory.
- Per-module list of versions bumped.
- JVM flag changes.
- Class-removal actions on any vendored JARs.
- SCA scan output before/after.
- Behaviour-test result.
- Rollback plan.
- Label: `sec-auto-remediation`.
## Stop conditions
- A vendored / shaded JAR cannot be safely modified
(signed, license-restricted). Triage with a note about the
vendor.
- The application uses Log4j 1.x and replacement requires API
changes. Triage; the right path is a separate
Log4j-1-to-2-or-reload4j migration.
- Tests fail in a way that suggests a real behaviour change in
Log4j 2.17.1+ — read the release notes and document.
## Scope
- Do not bundle other CVE bumps in this PR.
- Do not modify application logging configuration beyond what
the recipe requires.
- Do not remove `JndiManager` or other classes; only
`JndiLookup.class` is the fix.Verification — what the reviewer looks for
- Both
log4j-coreandlog4j-apiare at the same patched version. - The JVM flag is applied at the deployment layer (Dockerfile, Helm values, systemd unit), not just in a test config.
- For vendored JARs: the
JndiLookup.classentry is gone. Confirm withunzip -l. - The behaviour test in the PR exercised the actual logger path the application uses (not a synthetic logger).
- The PR did not silently bump unrelated dependencies.
Watch for
- Shaded uber-JARs. Some applications shade Log4j into a bigger JAR. Bumping the dependency upstream isn’t enough; the shaded copy needs the patched version baked in.
- Java 6 / Java 7 targets. The patch backports for those runtimes are 2.3.2 and 2.12.4. Do not silently bump to 2.17.1 on a Java 7 build.
log4j-1.x. A different bug surface (CVE-2019-17571 deserialization, CVE-2022-23305 SQL appender). The fix is migration to 2.x or reload4j; the recipe above does not cover it.- JNDI is broader than Log4j. A Log4j-clean codebase can still have JNDI-injection bugs in other libraries (Spring, H2 Console, JNDI lookups in custom code). This recipe doesn’t catch those.
- The flag is not enough alone.
formatMsgNoLookups=truewas a partial mitigation pre-2.16; some pattern-layout configurations still resolved lookups. The upgrade is the durable fix.
Related
- Vulnerable Dependency Remediation — the generic workflow this recipe specialises.
- Classic Vulnerable Defaults → Java ObjectInputStream — adjacent Java deserialization risks.