Dealing with the Critical Log4j Vulnerability

Table of Contents

Introduction

A critical remote code execution (RCE) vulnerability has been identified in the popular Apache Log4j logging library that affects versions 2.0 up to and including 2.14.1. This vulnerability has affected a very large number of JVM-based systems. For more information on the vulnerability itself, see CVE-2021-44228.

Update (December 22, 2021): Since the first post, two other vulnerabilities have been identified - CVE-2021-45046 and CVE-2021-45105 - so make sure to go over the different sections for updated instructions.

This vulnerability is being actively exploited. All Gradle users should assess whether their software projects are vulnerable and, if necessary, update to Log4j 2.17.0 or newer as soon as possible. We have provided instructions below on how to identify and prevent this vulnerability in your project.

We strongly recommended that you configure your Gradle build to reject any vulnerable version of Log4j using a dependency constraint.

In addition to your project dependencies, we also recommend protecting your build dependencies as documented below.

Note that the Gradle Build Tool itself is not impacted by this vulnerability as it does not use Log4j. Gradle uses SLF4J and a custom logging implementation not susceptible to the vulnerable string substitution.

The Gradle Scala plugin uses the Zinc Scala compiler that has a dependency on a vulnerable version of Log4j. However, in this case Gradle also supplies its own logging implementation and Log4j is not used by default.

Updates to this post:

Protecting your project dependencies #

1. Identify if your project uses a vulnerable Log4j version #

First, verify if your project uses the vulnerable Log4j version using the dependencies report or a Build Scan™. See viewing and debugging dependencies for details.

All versions of org.apache.logging.log4j:log4j-core between 2.0 and 2.16.0 (inclusive) are vulnerable.

2. Upgrade the Log4j dependency to a non-vulnerable version #

Upgrade the Log4j dependency in the dependencies block of the build scripts for each subproject or in your version catalog in the case you are using central declaration of dependencies.

Update (December 14, 2021): Log4j released 2.16.0 which disables and removes support for the feature at the heart of the vulnerability. In some non-default configurations, software could still be vulnerable with 2.15.0. To be absolutely certain, you should update to 2.16.0. The instructions below have been modified to use 2.16.0.

Update (December 22, 2021): Log4j released 2.17.0 which fixes yet another vulnerability. To be absolutely certain, you should update to 2.17.0. The instructions below have been modified to use 2.17.0.

3. Prevent accidental resolution of a vulnerable Log4j version in your project #

Given the critical severity of this vulnerability, we recommend taking the additional step described below in order to prevent accidental inclusion of a vulnerable version. Note that even if you are not using Log4j directly, the vulnerable version may still be resolved transitively through one your dependencies.

Use the dependency constraints feature to make sure that your project cannot resolve an impacted Log4j version by adding the following snippet to your Gradle build:

dependencies {
    constraints {
        implementation("org.apache.logging.log4j:log4j-core") {
            version {
                strictly("[2.17, 3[")
                prefer("2.17.0")
            }
            because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities")
        }
    }
}

The constraint will not be activated unless log4j-core appears in the dependency graph. The constraint will either forcefully upgrade the dependency to at least 2.17.0 or fail the build if the strict version constraint cannot be satisfied.

Note that using the implementation configuration here will cover the default setup of a Java library or application. But if you have custom configurations or more advanced setup, you should also add this constraint to additional configurations.

In addition, if you publish your library with such a constraint defined with Gradle Module Metadata, it will also cause any builds consuming your library to fail if they attempt to resolve a vulnerable version of log4j-core.

4. Prevent using a vulnerable Log4j version organization-wide #

Your organization may leverage shared plugins that are applied to all projects. In this case, you can also apply the constraint described above to all the projects in the organization.

If you use precompiled script plugins, simply copy the above snippet to the script applied to all your JVM projects. If you use binary plugins, here is the Java code equivalent to the DSL snippet:

project.getDependencies().constraints(constraints -> {
    constraints.add("implementation", "org.apache.logging.log4j:log4j-core", c -> {
        c.version(v -> {
            v.strictly("[2.17, 3[");
            v.prefer("2.17.0");
        });
        c.because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities");
    });
});

Protecting your build dependencies #

Update (December 15, 2021): You do not need to apply this to Gradle 7.3.2 and above. Gradle automatically requires the version of Log4J to be 2.16.0 or higher.

Update (December 22, 2021): You do not need to apply this to Gradle 7.3.3 and above. Gradle automatically requires the version of Log4J to be 2.17.0 or higher. Gradle 6.9.2 also does this for users still on the 6.x line.

In addition to project dependencies, your project probably uses either internal or third-party Gradle plugins. These plugins also have their own dependencies that may accidentally bring a vulnerable Log4j dependency to the build classpath.

In other words, your build logic may be vulnerable in the same way that your production code. While such vulnerabilities are likely harder to exploit, you can also protect your build dependencies with the snippet below:

buildscript {
    dependencies {
        constraints {
            classpath("org.apache.logging.log4j:log4j-core") {
                version {
                    strictly("[2.17, 3[")
                    prefer("2.17.0")
                }
                because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities")
            }
        }
    }
}

The snippet should be applied to the buildscript block in each build script and also to the settings.gradle(.kts) file, and ensures only Log4j 2.17.0 and above are resolvable as build dependencies. The statement must be at the top of the file.

Protecting Plugin Portal users #

Given the severity of the initial Log4j vulnerability, the Gradle team wanted to improve the situation for users of the Plugin Portal. We are taking steps to make sure that no new plugin can have a dependency on a vulnerable Log4j version. The following changes are available already and will be made mandatory in a later update.

As a Gradle plugin author, it is possible that you have either direct, or transitive dependencies on the vulnerable Log4j versions. In order to protect your plugin users, Gradle has added new validation rules to its plugin-publish plugin.

We have released version 0.19.0 of the Plugin Publish Plugin which automatically detects vulnerable Log4j plugin dependencies and, if any are found, blocks the plugin publication by failing the build. There is no automated upgrade as normally a Gradle plugin does not need Log4j since the Gradle runtime does not do its logging with this library. It is the job of the plugin author to fix the problem by removing the dependency or upgrading it.

Using this version of the Plugin Publish Plugin will become mandatory in the near future, by having the Plugin Portal reject any publications done with older versions of the plugin.

Gradle Enterprise products #

Several Gradle Enterprise products were impacted by the Log4j vulnerability.

New versions of Gradle Enterprise, Test Distribution Agent and Build Cache Node were released December 13, 2021.

Update (December 22, 2021): Gradle Enterprise 2021.4 upgrades Log4j to 2.17.0

Feedback #

Let us know if you have any questions on our forums or Gradle Community Slack.

Discuss