Caring for your dependency garden: An approach to Android Dependency Management

Part 4: Pulling out the weeds — Suspicious and vulnerable dependencies

Katie Barnett
Bilue Product Design & Technology Blog
4 min readAug 8, 2022

--

A man dressed in overalls holding a spade looks suspiciously at a row of plants.
Time to address those suspicious looking weeds. (image by E.F.S. on shutterstock.com)

If you haven’t yet, check out the start of this series with Part 1 to find out the why of managing dependencies and some useful first steps to take.

With such a reliance on a tree of open source projects (which may or may not be maintained by the same people that started them — if at all) it is hard to know if some suspect or bad code has been included along the way which could inadvertently share user data to a third party or otherwise do something that is not documented or expected by those consuming a particular dependency. You just need to look at stories like the Log4j incident to see this can happen to anyone and have far reaching consequences.

When building Android apps we also need to keep on top of any dependencies we add or update to make sure we are not including anything we don’t intend to. Just like when planting a new plant we want to make sure there are no pests coming along for the ride which may infect our whole garden bed. Unless you are across every changelog for the libraries you are using, reviewing their code changes and are cross referencing these with vulnerability announcements on security blogs, this is a hard job to do manually. Relying on dependencies that are well used by the community and are recommended by Google and other reputable sources that you trust is always the best starting point but this can come undone when open source projects are handed on to different owners who may not be as scrupulous as their original authors.

As with the other advice I have shared in this series, automation and integration into build scripts and CI is the best method here and the Dependency Check Plugin is a great starting point. This plugin will run through your dependencies and will report on known vulnerabilities. This of course relies on issues to be discovered and reported but hopefully with community support these databases will be kept up to date.

To include the plugin add the following to your root build.gradle file (full documentation for including in a gradle project here), with dependency_check_version being the current plugin version (found here).

The report can be run as a gradle task for the whole project (all modules) using ./gradlew dependencyCheckAggregate and a report with suggestions will be printed in the console.

The console report is somewhat hard to understand, it is better to look at the HTML report which can be found by default at /build/reports/dependency-check-report.html.

An example of the report is as follows (truncated to save space):

The visual report has a lot more information and you can then click on the links supplied to get more information.

Summary for the dependency check report.
Summary for the dependency check report.
Detail for one of the issues found in the dependency check report.
Detail for one of the issues found in the dependency check report.

For example in the above, the issue related to the detekt plugin is CVE-2022–0272, I was able to fix it by upgrading detekt from version 1.18.0 to 1.21.0.

The dependencyCheckAggregate gradle task can take time to run on a large project so it is recommend to schedule this to run periodically on the CI (it also has caching options which you can tweak for performance). You can add the outputDirectory configuration to put the report through to your CI artefact directory using the following configuration in your root build.gradle file (shown in this example with an environment variable from Bitrise — note if you are running this on your own environment you will want to comment out the use of a CI environment variable otherwise you will get java.io.File error):

In the above configuration the failOnError and failBuildOnCVSS values are set to not cause a failed build. These values can be tweaked depending on the application and the tolerance for false positives and whether you want your build to fail if issues are found or just review the output manually. More information can be found on how this works and what values to use here and how to suppress false positives can be found here.

In my testing I have found that a lot of the items it reported are false positives or without clear ways to address them. You will need to review these results and evaluate if you need to fix them or whether you can safely ignore them. Because of this, the above config and CI setup example has been done so that the build will not fail if issues are found, instead a report will be produced so the results can be reviewed manually. If the configuration is tightened and the suppression list is kept up to date so that you can reliably trust the results it can be adjusted to be a necessary step that must pass in a CI workflow.

Thank-you for bearing with me on this Android dependency management series, if you have any thoughts or useful dependency gardening tools you use, please share in the comments!

--

--