Since this month, anyone using the OWASP dependency check plugin from Jeremy Long(*1) needs to upgrade to version 9. The older versions are no longer supported and could fail to work.

It is also recommended to get an NVD api key(*2), else the NVD update can take a very long time. The NVD is the U.S. government repository of standards based vulnerability management data represented using the Security Content Automation Protocol (SCAP) (*3). Since most of us are using a build environment, we don’t want to create a key for every project, but if we do not, we might get rate-limit errors.

This is why NVD suggest to use a local (or centralised) cache of the nvd files. In this post I will explain how to do that.

Get the NVD files to your (local) machine

This is done by using the Open Vulnerability Project’s(*4) cli tool: vulnz. It is a java based tool so you need to build and install it. The Open Vulnerability Project is a collection of Java libraries and a CLI to work with various vulnerability data-sources (NVD, GitHub Security Advisories, CISA Known Exploited Vulnerablity Catalog, FIRST Exploit Prediction Scoring System (EPSS), etc.). Jeremy Long is one of the main contributors of this project.

git clone git@github.com:jeremylong/Open-Vulnerability-Project.git
cd Open-Vulnerability-Project
./gradlew vulnz:build
cd vulnz/build/libs

Now you have a java file that can be used to get the files needed. The first time you call this, it might take up to 10 minutes to run.

./vulnz.jar cve --apikey=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --cache --directory ./cache

If you get an out-of-memory error, you can try running it with a bit more memory:

java -Xmx2g -jar ./vulnz.jar cve --apikey=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --cache --directory ./cache

Now if you cd into the ./cache folder, it should look something like this:

jbrugman@computername cache % ls -ltr
total 238672
-rw-r--r--  1 jbrugman  staff   3798839 18 jan 16:17 nvdcve-2012.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2012.meta
-rw-r--r--  1 jbrugman  staff  14982741 18 jan 16:17 nvdcve-2023.json.gz
-rw-r--r--  1 jbrugman  staff       145 18 jan 16:17 nvdcve-2023.meta
-rw-r--r--  1 jbrugman  staff   3312453 18 jan 16:17 nvdcve-2011.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2011.meta
-rw-r--r--  1 jbrugman  staff  13119491 18 jan 16:17 nvdcve-2022.json.gz
-rw-r--r--  1 jbrugman  staff       144 18 jan 16:17 nvdcve-2022.meta
-rw-r--r--  1 jbrugman  staff   3330878 18 jan 16:17 nvdcve-2010.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2010.meta
-rw-r--r--  1 jbrugman  staff  12532086 18 jan 16:17 nvdcve-2021.json.gz
-rw-r--r--  1 jbrugman  staff       145 18 jan 16:17 nvdcve-2021.meta
-rw-r--r--  1 jbrugman  staff   9058667 18 jan 16:17 nvdcve-2020.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2020.meta
-rw-r--r--  1 jbrugman  staff   4055630 18 jan 16:17 nvdcve-2009.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2009.meta
-rw-r--r--  1 jbrugman  staff   2962182 18 jan 16:17 nvdcve-2008.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2008.meta
-rw-r--r--  1 jbrugman  staff   7924987 18 jan 16:17 nvdcve-2019.json.gz
-rw-r--r--  1 jbrugman  staff       142 18 jan 16:17 nvdcve-2019.meta
-rw-r--r--  1 jbrugman  staff   2914030 18 jan 16:17 nvdcve-2007.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2007.meta
-rw-r--r--  1 jbrugman  staff   7020129 18 jan 16:17 nvdcve-2018.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2018.meta
-rw-r--r--  1 jbrugman  staff   2637365 18 jan 16:17 nvdcve-2006.json.gz
-rw-r--r--  1 jbrugman  staff       142 18 jan 16:17 nvdcve-2006.meta
-rw-r--r--  1 jbrugman  staff   6403948 18 jan 16:17 nvdcve-2017.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2017.meta
-rw-r--r--  1 jbrugman  staff   1956119 18 jan 16:17 nvdcve-2005.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2005.meta
-rw-r--r--  1 jbrugman  staff   3233184 18 jan 16:17 nvdcve-2016.json.gz
-rw-r--r--  1 jbrugman  staff       142 18 jan 16:17 nvdcve-2016.meta
-rw-r--r--  1 jbrugman  staff   1076293 18 jan 16:17 nvdcve-2004.json.gz
-rw-r--r--  1 jbrugman  staff       142 18 jan 16:17 nvdcve-2004.meta
-rw-r--r--  1 jbrugman  staff   2634851 18 jan 16:17 nvdcve-2015.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2015.meta
-rw-r--r--  1 jbrugman  staff    598141 18 jan 16:17 nvdcve-2003.json.gz
-rw-r--r--  1 jbrugman  staff       140 18 jan 16:17 nvdcve-2003.meta
-rw-r--r--  1 jbrugman  staff   3943878 18 jan 16:17 nvdcve-2014.json.gz
-rw-r--r--  1 jbrugman  staff       142 18 jan 16:17 nvdcve-2014.meta
-rw-r--r--  1 jbrugman  staff   1663893 18 jan 16:17 nvdcve-2002.json.gz
-rw-r--r--  1 jbrugman  staff       143 18 jan 16:17 nvdcve-2002.meta
-rw-r--r--  1 jbrugman  staff   4185442 18 jan 16:17 nvdcve-2013.json.gz
-rw-r--r--  1 jbrugman  staff       141 18 jan 16:17 nvdcve-2013.meta
-rw-r--r--  1 jbrugman  staff    709660 18 jan 16:17 nvdcve-2024.json.gz
-rw-r--r--  1 jbrugman  staff       140 18 jan 16:17 nvdcve-2024.meta
-rw-r--r--  1 jbrugman  staff    635158 18 jan 16:17 nvdcve-modified.json.gz
-rw-r--r--  1 jbrugman  staff       140 18 jan 16:17 nvdcve-modified.meta
-rw-r--r--  1 jbrugman  staff      1169 18 jan 16:17 cache.properties

So nice, we have the files we need to have our dependency check running again. Since I want to test it on my local machine, I just run a simple webserver from within this cache folder. For convenience, I use the default https.server that’s part of python.

python3 -m http.server --directory .

Configure your application

I use gradle in this project; all examples are based on it.

First edit your build.gradle file, to add the dependency:

plugins {
  id "org.owasp.dependencycheck" version "9.0.9"
  id "java"
}

Now we need to configure(*5) the plugin, so it gets the files from the proper location:

dependencyCheck {
  failBuildOnCVSS = 7
  failOnError = true
  suppressionFile = './owasp/suppressions.xml'

  // Make sure the nvd files are fetched from the own central server.
  nvd {
    datafeedUrl="http://localhost:8000/nvdcve-{0}.json.gz"
  }
}

That’s it, just configure the datafeedUrl! Now test it:

# clean your local cache
./gradlew dependencyCheckPurge

> Configure project :
Inferred project: splashmicroservice, version: 0.295.0-dev.16.uncommitted+combine.prs.branch.ae18b48

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

# run the dependency check
./gradlew dependencyCheckAggregate --no-daemon --stacktrace

...

Well, if everything works as intended, you should see in your webserver log that it gets the files needed to fill the h2 database that the plugin uses.

# log from the python webserver
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:13] "GET /cache.properties HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:13] "GET /nvdcve-2012.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:13] "GET /nvdcve-2023.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2011.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2022.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2010.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2021.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2020.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2009.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2008.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2019.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2007.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2018.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2006.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2017.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2005.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2016.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2004.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2015.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2003.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2014.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2002.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2013.json.gz HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [18/Jan/2024 16:19:14] "GET /nvdcve-2024.json.gz HTTP/1.1" 200 -

All that’s left to do is set up the server, so it gets those files on a daily base, and make sure your config points to that central managed server. You could for example use an s3 bucket on AWS to host your files and use that toe serve your cached nvd files. The configuration would then look like this:

dependencyCheck {
  failBuildOnCVSS = 7
  failOnError = true
  suppressionFile = '.circleci/owasp/suppressions.xml'
  nvd {
    datafeedUrl="https://mycompany-owasp-files.s3.eu-west-1.amazonaws.com/nvdcve-{0}.json.gz"
  }
}

Recapitulation

If you have your CI/CD set up to handle your build, you hardly have to change anything. All you need to do is:

  • Create a cron-job to update your nvd-files on a daily basis using the vulnz cli tool

  • Host those files on a (secure) webserver that your CI/CD environment can reach

  • Alter the configuration of your build.gradle to point to that given webserver

shadow-left