Skip to content

Latest commit

 

History

History
150 lines (90 loc) · 10.9 KB

File metadata and controls

150 lines (90 loc) · 10.9 KB

Detecting and resolving dependency vulnerabilities in Gradle projects

This is a simple project demonstrating how to use the dependency-submission GitHub action to detect vulnerable dependencies in a Gradle project, and various techniques to address these vulnerabilities.

You may find it useful to fork this repository, which will allow you to follow this guide, view and resolve Dependabot alerts. Note that GitHub Actions workflows are not automatically enabled for repository forks. To start the process, you'll need to:

  1. Fork the repository
  2. Navigate to "Settings -> Code security and analysis" to enable Dependency graph and Dependabot alerts (see below)
  3. Navigate to the "Actions" tab to enable GitHub Actions workflows
  4. Push a commit to the 'main' branch in order to trigger the initial dependency-submission workflow to run. A change to the README will be sufficient.

Setting up the repository to detect vulnerable dependencies

In order to receive alerts about any vulnerable dependencies for this repository:

  1. Dependency graph and Dependabot alerts are enabled
image
  1. A simple dependency-submission workflow is configured to run on any push to the main branch

# Submits a dependency graph on every push to 'main'
name: Dependency Submission
on:
push:
branches:
- main
permissions:
contents: write
jobs:
dependency-submission:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Set up the JDK used to run Gradle
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v3
with:
build-scan-publish: true
build-scan-terms-of-service-url: "https://gradle.com/terms-of-service"
build-scan-terms-of-service-agree: "yes"

Note that the workflow is configured to publish a Build Scan® on each run. This Build Scan will contain information about your project structure and dependencies, and will be useful later as we attempt to identify and resolve any vulnerable dependencies.

See the full dependency-submission documentation for more details on adding a dependency-submission workflow.

Viewing all dependencies for this repository

Executing the dependency-submission workflow will submit the full graph of resolved dependencies to your repository. You can view all of these dependencies, and search for a particular dependency via the GitHub dependency graph view.

image

Note that all dependencies reported by the action will be tagged with Detected by GitHub Dependency Graph Gradle Plugin.

Reviewing vulnerabilities reported for this repository

After executing the dependency-submission workflow, the repository has 5 current Dependabot alerts for vulnerable dependencies. These are not publicly visible in the repo, but here is the list:

image

In the following sections we will step through the process of investigating, isolating and addressing different types of vulnerabilities.

Updating a direct dependency to non-vulnerable version

In this example repository, a dependency on org.apache.commons:commons-text:1.9 results in the following Dependabot alert:

image

In this simple case, the vulnerable dependency is declared directly in the Gradle project, and a newer, non-vulnerable version is available.

The fix is as simple as bumping the version in the project. Here is a pull-request that will address this vulnerability.

image

Updating a vulnerable transitive dependency by updating a direct dependency

We see 2 vulnerabilities reported for org.apache.commons:commons-compress:1.24.0, like this:

image

But there isn't anywhere in our Gradle project where we depend on commons-compress, which means this vulnerability must involve a transitive dependency. The first step is to identify which direct dependency is responsible.

The easiest way to do this is with a Gradle Build Scan®, which is why our workflow is configured to automatically publish a Build Scan for every dependency submission. You'll find the Build Scan link in the summary for each workflow run.

image

By inspecting the Build Scan for the latest submission on 'main', we can see that commons-compress is required by io.minio:minio:8.5.8, which is a direct dependency of our project.

image

Searching for newer versions reveals that there's an updated version of minio available (8.5.9), and when we update our project to this version, the commons-compress library is updated to 1.26.0.

Here's the pull-request that will update the version of minio, resolving the 2 Dependabot alerts triggered by org.apache.commons:commons-compress:1.24.0.

image

Updating a transitive dependency using a dependency constraint

At times when you won't be able to update a direct dependency to resolve a transitive dependency vulnerability. This can occur if there isn't a newer version of the direct dependency available, or perhaps your project isn't compatible with the newer version.

In this case, you can directly control the transitive dependency version using a dependency constraint. A dependency contraint allows you to specify a transitive dependency version to use, without adding a direct dependency on that version.

This pull-request adds a dependency constraint that causes the build to use a newer version of commons-compress, thereby resolving the Dependabot alert.

image

If you inspect the resulting Build Scan, you can see that the version of commons-compress is updated, but the version of minio is not changed.

image

Updating a Plugin classpath dependency using a dependency constraint

In addition to things you declare in a dependencies block, any Gradle plugins that you apply to your build will likely have library dependencies. Vulnerabilities in these plugin dependencies are detected by the dependency-submission action.

The final 2 Dependabot alerts in this project are due to com.squareup.okio:okio-jvm:3.2.0 and com.squareup.okio:okio:3.2.0.

image

When searchinig for 'okio' in the Dependencies section of the Build Scan, we note that there is a dependency on version 3.6.0 (required by io.minio:minio:8.5.8), but there is no dependency on vulnerable version 3.2.0.

The reason you can't see 3.2.0 is because these vulnerable versions are actually brought in by the com.github.ben-manes.versions plugin and are listed separately.

You can see this by searching in the Build Dependencies section of the Build Scan instead.

image

Although vulnerable plugin dependencies like this can be trickier to identify, they can be resolved in much the same way as regular transitive dependencies, either by updating to a new version of the plugin, or by using a dependency constraint.

In this case there is no newer version of the plugin available, so we must add a dependency constraint to force a newer version of okio to be used.

This pull request adds a dependency constraint to the buildscript classpath, which fixes the security vulnerablitity in okio that is introduced by the com.github.ben-manes.versions plugin.

image

The resulting Build Scan demonstrates that the build dependencies no longer include the vulnerable dependency versions.

image