In modern software development, applications are built using numerous third-party dependencies, making supply chain security a critical concern. OWASP Dependency-Check is an open-source tool that scans your project dependencies for known vulnerabilities, helping you identify and remediate security risks before they reach production. This guide explores how to effectively integrate and use Dependency-Check in Java projects.
What is OWASP Dependency-Check?
Dependency-Check is a Software Composition Analysis (SCA) tool that identifies project dependencies and checks against known vulnerability databases. It works by creating a fingerprint of each dependency and comparing it against the National Vulnerability Database (NVD) and other sources.
Key Features:
- Multi-language Support: Java, .NET, JavaScript, Python, Ruby, PHP, and more
- Multiple Database Support: NVD, Retire.js, NPM Advisory, etc.
- Build Tool Integration: Maven, Gradle, Ant, SBT
- CI/CD Friendly: Command-line interface and plugins
- Evidence-Based Analysis: Uses filename, hashes, and package information
How Dependency-Check Works
Dependency-Check Workflow: 1. Scan Dependencies → 2. Collect Evidence → 3. Generate Fingerprint → 4. Check Databases → 5. Generate Report
Analysis Process:
- Dependency Collection: Identifies all dependencies in your project
- Evidence Gathering: Collects information from filenames, hashes, and package metadata
- Fingerprinting: Creates unique identifiers for each dependency
- Vulnerability Matching: Compares fingerprints against vulnerability databases
- Reporting: Generates detailed reports with vulnerability information
Installation and Setup
1. System Requirements
- Java 8 or higher
- 4GB+ RAM (for large projects)
- Internet access (for database updates)
2. Download Standalone CLI
# Download latest version wget https://github.com/jeremylong/DependencyCheck/releases/download/v9.0.7/dependency-check-9.0.7-release.zip unzip dependency-check-9.0.7-release.zip cd dependency-check/bin
3. Verify Installation
./dependency-check.sh --version # or on Windows dependency-check.bat --version
Maven Integration
1. Basic Maven Plugin Configuration
<project> <build> <plugins> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>9.0.7</version> <configuration> <format>HTML</format> <failBuildOnAnyVulnerability>true</failBuildOnAnyVulnerability> <failOnCVSS>7</failOnCVSS> </configuration> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
2. Advanced Maven Configuration
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>9.0.7</version>
<configuration>
<!-- Report Formats -->
<formats>HTML,JSON,XML</formats>
<!-- Failure Configuration -->
<failBuildOnAnyVulnerability>true</failBuildOnAnyVulnerability>
<failOnCVSS>8</failOnCVSS>
<!-- Scan Configuration -->
<scanSet>
<scan>
<fileSet>
<directory>${project.basedir}</directory>
<includes>
<include>**/*.jar</include>
<include>**/package-lock.json</include>
</includes>
</fileSet>
</scan>
</scanSet>
<!-- Suppression File -->
<suppressionFiles>
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
</suppressionFiles>
<!-- Database Configuration -->
<cveValidForHours>24</cveValidForHours>
<nvdApiKey>${nvd.api.key}</nvdApiKey>
<!-- Performance Tuning -->
<jarAnalyzerEnabled>true</jarAnalyzerEnabled>
<nodeAnalyzerEnabled>true</nodeAnalyzerEnabled>
<nodeAuditAnalyzerEnabled>true</nodeAuditAnalyzerEnabled>
<retireJsAnalyzerEnabled>true</retireJsAnalyzerEnabled>
</configuration>
</plugin>
3. Running with Maven
# Basic scan mvn dependency-check:check # Skip tests for faster scanning mvn dependency-check:check -DskipTests # Update local database first mvn dependency-check:update-only mvn dependency-check:check # With custom properties mvn dependency-check:check -DfailBuildOnAnyVulnerability=false
Gradle Integration
1. Basic Gradle Plugin Setup
// build.gradle.kts
plugins {
id("org.owasp.dependencycheck") version "9.0.7"
}
dependencyCheck {
format = listOf("HTML", "JSON", "XML")
failBuildOnCVSS = 8.0f
analyzers.assemblyEnabled = false
}
tasks.named("dependencyCheckAnalyze") {
dependsOn("assemble")
}
2. Advanced Gradle Configuration
dependencyCheck {
// Output Configuration
formats = listOf("HTML", "JSON", "XML")
outputDirectory = file("${buildDir}/reports/dependency-check")
// Failure Configuration
failBuildOnAnyVulnerability = true
failOnCVSS = 7.0f
// Scan Configuration
scanConfigurations = listOf("runtimeClasspath")
scanSet = files(
fileTree("src/main/resources") {
include("**/*.jar")
}
)
// Suppression File
suppressionFile = "dependency-check-suppressions.xml"
// Database Configuration
cveValidForHours = 12
nvd.api.key = project.properties["nvdApiKey"] as? String
// Analyzer Configuration
analyzers {
assemblyEnabled = false
jarAnalyzerEnabled = true
nodeEnabled = true
nodeAuditEnabled = true
retireJsEnabled = true
swiftEnabled = false
cocoapodsEnabled = false
}
// Data Mirror Configuration
data {
directory = "${project.rootDir}/dependency-check-data"
}
}
3. Running with Gradle
# Basic scan ./gradlew dependencyCheckAnalyze # Update database ./gradlew dependencyCheckUpdate # Generate aggregate report for multi-project ./gradlew dependencyCheckAggregate
Standalone CLI Usage
1. Basic CLI Scan
# Scan a Java project ./dependency-check.sh --project "My Application" --scan "target/*.jar" --out reports/ # Scan with multiple paths ./dependency-check.sh \ --project "My Microservice" \ --scan "service-a/target/*.jar" \ --scan "service-b/target/*.jar" \ --scan "frontend/package-lock.json" \ --format HTML \ --format JSON \ --out ./security-reports
2. Advanced CLI Configuration
./dependency-check.sh \ --project "Enterprise Application" \ --scan "/path/to/application" \ --suppression "dependency-check-suppressions.xml" \ --enableRetired \ --failOnCVSS 8 \ --nvdApiKey $NVD_API_KEY \ --cveValidForHours 6 \ --data "/opt/dependency-check/data" \ --connectionTimeout 60000 \ --proxyserver proxy.company.com \ --proxyport 8080 \ --hints hints.xml
Suppression Files and False Positives
1. Creating Suppression File
<?xml version="1.0" encoding="UTF-8"?> <suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd"> <!-- Suppress by CVE --> <suppress> <notes><![CDATA[ False positive - this vulnerability doesn't affect our usage ]]></notes> <cve>CVE-2023-12345</cve> </suppress> <!-- Suppress by Dependency --> <suppress> <notes><![CDATA[ We've validated this dependency is safe in our context ]]></notes> <gav>com.example:library:1.2.3</gav> <cve>CVE-2023-67890</cve> </suppress> <!-- Suppress All Vulnerabilities for a Dependency --> <suppress base="true"> <notes><![CDATA[ Internal library with no external dependencies ]]></notes> <gav>com.company:internal-utils:2.0.0</gav> </suppress> <!-- Suppress by File Hash --> <suppress> <notes><![CDATA[ Custom patched version of the library ]]></notes> <sha1>a1b2c3d4e5f6789012345678901234567890123</sha1> </suppress> <!-- Suppress Until Date --> <suppress until="2024-12-31"> <notes><![CDATA[ Waiting for patch to be available ]]></notes> <gav>org.springframework:spring-core:5.3.8</gav> <cve>CVE-2023-98765</cve> </suppress> <!-- Suppress by Vulnerability Type --> <suppress> <notes><![CDATA[ This is a build-time only dependency ]]></notes> <gav>org.apache.maven.plugins:maven-compiler-plugin:3.11.0</gav> <vulnerabilityName>.*denial of service.*</vulnerabilityName> </suppress> </suppressions>
2. Auto-generate Suppression Template
# Generate suppression template from existing report ./dependency-check.sh \ --project "Generate Suppressions" \ --scan "target/dependency" \ --format "JSON" \ --out "reports" # Then convert findings to suppression format
CI/CD Integration
1. GitHub Actions Workflow
name: Dependency Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 2 * * 1' # Weekly on Monday at 2 AM
jobs:
dependency-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Dependency-Check data
uses: actions/cache@v3
with:
path: ~/.dependency-check/data
key: ${{ runner.os }}-dependency-check-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-dependency-check-
- name: Run Dependency-Check
run: |
mvn org.owasp:dependency-check-maven:check
env:
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
- name: Upload Dependency-Check report
uses: actions/upload-artifact@v3
with:
name: dependency-check-report
path: target/dependency-check-report.html
retention-days: 30
- name: Check for critical vulnerabilities
run: |
if grep -q "CRITICAL" target/dependency-check-report.html; then
echo "Critical vulnerabilities found!"
exit 1
fi
2. Jenkins Pipeline
pipeline {
agent any
tools {
maven 'Maven_3.8'
}
stages {
stage('Dependency Check') {
steps {
script {
// Update vulnerability database
sh 'mvn org.owasp:dependency-check-maven:update-only'
// Run dependency check
sh 'mvn org.owasp:dependency-check-maven:check -DfailBuildOnCVSS=8'
}
}
post {
always {
dependencyCheckPublisher(
pattern: '**/dependency-check-report.xml',
failedTotalHigh: '10',
failedTotalCritical: '1',
unstableTotalHigh: '5',
unstableTotalCritical: '0'
)
archiveArtifacts artifacts: '**/dependency-check-report.*', fingerprint: true
}
}
}
}
}
Advanced Configuration and Customization
1. Custom Analyzers Configuration
<plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>9.0.7</version> <configuration> <analyzers> <!-- Enable/disable specific analyzers --> <jarAnalyzerEnabled>true</jarAnalyzerEnabled> <nodeAnalyzerEnabled>true</nodeAnalyzerEnabled> <nodeAuditAnalyzerEnabled>true</nodeAuditAnalyzerEnabled> <retireJsAnalyzerEnabled>true</retireJsAnalyzerEnabled> <composerAnalyzerEnabled>false</composerAnalyzerEnabled> <pythonAnalyzerEnabled>false</pythonAnalyzerEnabled> <rubyAnalyzerEnabled>false</rubyAnalyzerEnabled> <cocoaPodsAnalyzerEnabled>false</cocoaPodsAnalyzerEnabled> <swiftAnalyzerEnabled>false</swiftAnalyzerEnabled> <archiveAnalyzerEnabled>true</archiveAnalyzerEnabled> <assemblyAnalyzerEnabled>true</assemblyAnalyzerEnabled> <nugetconfAnalyzerEnabled>false</nugetconfAnalyzerEnabled> <nuspecAnalyzerEnabled>false</nuspecAnalyzerEnabled> <centralAnalyzerEnabled>true</centralAnalyzerEnabled> <nexusAnalyzerEnabled>false</nexusAnalyzerEnabled> <openSSLAnalyzerEnabled>true</openSSLAnalyzerEnabled> </analyzers> </configuration> </plugin>
2. Database Configuration
<configuration>
<connectionString>jdbc:h2:file:~/.dependency-check/data/dc;AUTOCOMMIT=ON</connectionString>
<dataDirectory>${user.home}/.dependency-check/data</dataDirectory>
<cveUrlModified>https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz</cveUrlModified>
<cveUrlBase>https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz</cveUrlBase>
<cveStartYear>2002</cveStartYear>
<cveValidForHours>12</cveValidForHours>
</configuration>
3. Proxy Configuration
<configuration> <proxyserver>proxy.company.com</proxyserver> <proxyport>8080</proxyport> <proxyusername>proxyuser</proxyusername> <proxypassword>proxypass</proxypassword> <nonProxyHosts>localhost|*.internal.company.com</nonProxyHosts> <connectionTimeout>60000</connectionTimeout> </configuration>
Integrating with Security Tools
1. SonarQube Integration
<plugin> <groupId>org.sonarsource.scanner.maven</groupId> <artifactId>sonar-maven-plugin</artifactId> <version>3.9.1.2184</version> </plugin> <!-- Run dependency check before SonarQube --> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>9.0.7</version> <executions> <execution> <id>dependency-check</id> <phase>verify</phase> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin>
2. Generating SARIF Reports for GitHub
<configuration> <formats>HTML,SARIF</formats> </configuration>
Custom Java Application Integration
1. Programmatic Usage
public class DependencyCheckRunner {
public void runDependencyCheck(File projectDir, File outputDir) throws Exception {
Engine engine = new Engine();
// Configure settings
Settings settings = engine.getSettings();
settings.setString(Settings.KEYS.AUTO_UPDATE, "true");
settings.setString(Settings.KEYS.SUPPRESSION_FILE,
"dependency-check-suppressions.xml");
settings.setString(Settings.KEYS.ANALYZER_NEXUS_ENABLED, "false");
// Configure database connection
settings.setString(Settings.KEYS.DB_CONNECTION_STRING,
"jdbc:h2:file:" + outputDir.getAbsolutePath() + "/odc;AUTOCOMMIT=ON");
try {
// Scan dependencies
engine.scan(projectDir);
// Analyze dependencies
engine.analyzeDependencies();
// Write reports
ReportGenerator reportGenerator = new ReportGenerator(
"My Application", engine.getDependencies(), engine.getSettings()
);
reportGenerator.generateReports(
outputDir.getAbsolutePath(),
new ReportGenerator.Format[] {
ReportGenerator.Format.HTML,
ReportGenerator.Format.JSON
},
"Dependency Check Report"
);
} finally {
engine.close();
}
}
}
2. Spring Boot Integration
@Component
public class DependencyCheckService {
private static final Logger logger = LoggerFactory.getLogger(DependencyCheckService.class);
@EventListener(ApplicationReadyEvent.class)
public void runSecurityScan() {
if (isSecurityScanEnabled()) {
logger.info("Starting dependency security scan...");
try {
runDependencyCheck();
logger.info("Dependency security scan completed");
} catch (Exception e) {
logger.error("Dependency security scan failed", e);
}
}
}
private void runDependencyCheck() throws Exception {
// Implementation using programmatic API
}
@Bean
@Profile("!prod")
public DependencyCheckRunner dependencyCheckRunner() {
return new DependencyCheckRunner();
}
}
Best Practices
1. Scan Frequency
- Pre-commit: Quick scans during development
- CI Pipeline: Full scans on pull requests
- Scheduled: Daily or weekly comprehensive scans
- Release Gates: Mandatory scans before production deployment
2. Vulnerability Management
public class VulnerabilityManagementService {
public VulnerabilityAssessment assessVulnerabilities(File dependencyCheckReport) {
List<Vulnerability> vulnerabilities = parseReport(dependencyCheckReport);
return vulnerabilities.stream()
.filter(this::isRelevant)
.filter(vuln -> vuln.getCvssScore() >= 7.0)
.collect(Collectors.toList());
}
private boolean isRelevant(Vulnerability vulnerability) {
// Filter out false positives and irrelevant vulnerabilities
return !vulnerability.isFalsePositive() &&
vulnerability.isExploitable() &&
!isBuildTimeOnly(vulnerability);
}
}
3. Risk Assessment Matrix
public enum RiskLevel {
CRITICAL(9.0, 10.0, "Immediate action required"),
HIGH(7.0, 8.9, "Address within 1 week"),
MEDIUM(4.0, 6.9, "Address within 1 month"),
LOW(0.1, 3.9, "Monitor and plan"),
NONE(0.0, 0.0, "No action required");
private final double minScore;
private final double maxScore;
private final String action;
// Constructor, getters...
public static RiskLevel fromCVSS(double cvssScore) {
for (RiskLevel level : values()) {
if (cvssScore >= level.minScore && cvssScore <= level.maxScore) {
return level;
}
}
return NONE;
}
}
Troubleshooting Common Issues
1. Performance Optimization
<configuration> <!-- Limit memory usage --> <jvmFlags> <jvmFlag>-Xmx4g</jvmFlag> <jvmFlag>-Xms1g</jvmFlag> </jvmFlags> <!-- Disable unused analyzers --> <analyzers> <pythonAnalyzerEnabled>false</pythonAnalyzerEnabled> <rubyAnalyzerEnabled>false</rubyAnalyzerEnabled> </analyzers> </configuration>
2. Database Update Issues
# Manual database update ./dependency-check.sh --updateonly --connectionTimeout 120000 # Use offline mode if updates fail ./dependency-check.sh --project "MyApp" --scan "target" --noupdate
3. Memory Issues with Large Projects
# Increase heap size export JAVA_OPTS="-Xmx8g -Xms2g" ./dependency-check.sh --project "LargeApp" --scan "."
Conclusion
OWASP Dependency-Check provides Java developers with a powerful tool for securing software supply chains by:
- Comprehensive Scanning: Detects vulnerabilities across multiple ecosystems
- Continuous Monitoring: Integrates seamlessly into CI/CD pipelines
- Actionable Reports: Provides detailed information for remediation
- Flexible Configuration: Adapts to various project requirements
- Enterprise Ready: Scales from small projects to large microservices architectures
By integrating Dependency-Check into your development workflow, you can proactively identify and address security vulnerabilities, reduce attack surfaces, and maintain the integrity of your software supply chain. The key to success is establishing a consistent scanning regimen, properly configuring suppression files for false positives, and integrating security scanning into your development culture.