The most surprising thing about scanning dependencies for CVEs is that you’re not actually finding vulnerabilities, you’re finding known advisories that might be exploitable.

Let’s see it in action. Imagine you have a pom.xml file for a Maven project:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
        </dependency>
    </dependencies>
</project>

You’ve configured OWASP Dependency-Check as a Jenkins plugin. In your Jenkins pipeline, you might have a step like this:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean install'
            }
        }
        stage('Dependency Scan') {
            steps {
                dependencyCheckPublisher publishProgress: true,
                                       scanAllUnmodified: true,
                                       skipDuplicateInfo: false,
                                       skipHigh: false,
                                       skipInfo: false,
                                       skipLow: false,
                                       skipMedium: false,
                                       suppressionFile: 'dependency-check-suppressions.xml',
                                       failBuildOnCVSS: 7.0,
                                       failBuildOnSeverity: 'HIGH'
            }
        }
    }
}

When this pipeline runs, the dependencyCheckPublisher step triggers the Dependency-Check tool. It analyzes the project’s dependencies (in this case, log4j-core version 2.17.1 and jackson-databind version 2.13.0). It consults its local NVD (National Vulnerability Database) and other curated data sources to find any CVEs associated with these specific library versions.

The problem Dependency-Check solves is the sheer volume and complexity of managing third-party libraries. Developers often pull in dozens, if not hundreds, of dependencies. Keeping track of which versions have known vulnerabilities is a manual nightmare. Dependency-Check automates this by creating a bill of materials (BOM) for your project and cross-referencing it with vulnerability advisories. It’s not just about Maven; it supports npm, PyPI, NuGet, RubyGems, and many more package managers.

Internally, Dependency-Check works by identifying your project’s dependencies and then querying its local database for matching CVEs. This database is updated regularly (you can configure how often). When a match is found, it reports the CVE ID, a description, the affected version range, and a CVSS (Common Vulnerability Scoring System) score. The Jenkins plugin then visualizes these findings directly in the Jenkins UI, allowing you to see the severity and link to the CVE details. You can configure it to fail the build if certain severity levels or CVSS scores are exceeded, enforcing a security gate.

The one thing most people don’t realize is that Dependency-Check primarily relies on matching product and version strings. If a CVE advisory doesn’t explicitly mention log4j-core version 2.17.1 but instead says "versions of Log4j prior to 2.17.2 are affected," Dependency-Check will flag it. However, if a vulnerability exists in a library but the advisory is poorly written, or if the library’s pom.xml or other metadata is incorrect, Dependency-Check might miss it. This is why it’s a supplement to other security practices, not a replacement.

After addressing all critical and high-severity CVEs, the next challenge will be managing false positives and understanding the true exploitability of reported vulnerabilities.

Want structured learning?

Take the full Jenkins course →