Ravindra BagaleCourses & study guides मराठी

Chapter 29: Scan Pipeline in Jenkins

29.4 OWASP Dependency-Check

Why: the problem

Suppose we are on an Infosys banking project. The bank's auditor asks one question: "Show me that no library in this app has a known vulnerability with a score above 7." Our Java app has 80 libraries, and each library pulls in more libraries. Nobody can check that by hand. OWASP Dependency-Check does it. It reads the dependency files, finds each library's identity (called a CPE), and looks it up in the US National Vulnerability Database (NVD). Each finding has a CVSS score from 0 to 10. We tell the tool: fail the build at 7 or above. Then the auditor gets a clean HTML report from every build, and Jenkins refuses to ship a risky library.

What we will build

The Dependency-Check scan for the badge API in three ways: the CLI on a Node project, the Maven plugin on the Java project, and the Jenkins plugin with a published report. You will add an NVD API key the safe way, fail the build at CVSS 7, and write a suppression file for a false positive.

What: every term in plain English

  • OWASP — Open Worldwide Application Security Project, a non-profit that makes free security tools.
  • Dependency — A library your app uses. A transitive dependency is a library your library uses.
  • NVD — National Vulnerability Database, the US public list of CVEs with scores.
  • NVD API key — A free key from NVD that makes the database download much faster. Stored as credential lab-nvd-key.
  • CVSS — Common Vulnerability Scoring System: 0-10. 7.0-8.9 HIGH, 9.0-10 CRITICAL.
  • CPE — A standard name for a product and version, used to match a library to CVEs.
  • Suppression file — An XML file that hides a false positive, with a note explaining why.
Download the CLI Check it runs Get an NVD key and save it in Jenkins Update the database once Scan the Node project Read the exit code Open the report
Read deps, match CVEs, score, gate at 7

How: step by step

  1. Download the CLI

    VER=10.0.3; curl -sLO https://github.com/jeremylong/DependencyCheck/releases/download/v$VER/dependency-check-$VER-release.zip && unzip -q dependency-check-$VER-release.zip -d /opt
    

    What it does: Installs the CLI into /opt/dependency-check. It needs Java 11+.

    Output

    (no output)
    
  2. Check it runs

    /opt/dependency-check/bin/dependency-check.sh --version
    

    What it does: Prints the version.

    Output

    Dependency-Check Core version 10.0.3
    
  3. Get an NVD key and save it in Jenkins

    Request at nvd.nist.gov/developers/request-an-api-key, then Credentials > Secret text, ID lab-nvd-key
    

    What it does: The key is free. Store it only in Jenkins.

    Output

    Credential lab-nvd-key created
    
  4. Update the database once

    /opt/dependency-check/bin/dependency-check.sh --updateonly --nvdApiKey "$NVD_API_KEY" --data /var/cache/odc
    

    What it does: Downloads the NVD data into a shared cache folder. The first time takes 10-20 minutes.

    Output

    [INFO] NVD API has 251,000 records in this update
    [INFO] Download Complete for NVD CVE - 2002 (12 seconds)
    ... [INFO] Begin database defrag
    
  5. Scan the Node project

    /opt/dependency-check/bin/dependency-check.sh --project badge-api --scan . --exclude "**/node_modules/**" --data /var/cache/odc --noupdate --format HTML --format JSON --out reports --failOnCVSS 7
    

    What it does: Scans package-lock.json, writes HTML and JSON, and fails on CVSS 7+.

    Output

    [INFO] Analysis Started
    [INFO] Finished Node.js Package Analyzer (1 seconds)
    [INFO] Analysis Complete (4 seconds)
    [INFO] Writing HTML report to: reports/dependency-check-report.html
    
  6. Read the exit code

    echo $?
    

    What it does: 0 means nothing at 7+. Non-zero means the gate closed.

    Output

    0
    
  7. Open the report

    xdg-open reports/dependency-check-report.html
    

    What it does: Shows each dependency, its CPE, CVEs and scores.

    Output

    (browser opens the report)
    

Example 1: Node

Stack. Node.js, Dependency-Check CLI

Goal. Node.js with the CLI inside Jenkins. The key comes from credentials.

Jenkinsfile

pipeline {
  agent { label 'scan' }
  options { timestamps(); timeout(time: 30, unit: 'MINUTES') }
  stages {
    stage('Checkout') { steps { checkout scm } }
    stage('Dependency-Check') {
      steps {
        withCredentials([string(credentialsId: 'lab-nvd-key', variable: 'NVD_API_KEY')]) {
          sh '''
            /opt/dependency-check/bin/dependency-check.sh \
              --project badge-api --scan . --exclude "**/node_modules/**" \
              --data /var/cache/odc --nvdApiKey "$NVD_API_KEY" \
              --format HTML --format XML --out reports --failOnCVSS 7
          '''
        }
      }
      post { always { archiveArtifacts artifacts: 'reports/dependency-check-report.*', allowEmptyArchive: true } }
    }
    stage('Live (lab)') {
      steps { echo 'All gates green: deploying badge-api to the lab' }
    }
  }
}

What each line does

  • withCredentials([string(credentialsId: 'lab-nvd-key', ...)]) — Puts the key in NVD_API_KEY only inside this block, and Jenkins masks it in logs.
  • --data /var/cache/odc — Shared DB folder on the agent so every build does not download NVD again.
  • --failOnCVSS 7 — Exit non-zero if any finding scores 7 or more.
  • post { always { archiveArtifacts ... } } — Keeps the HTML report even when the stage is red, so you can read why.
  • stage('Live (lab)') — Runs only if every stage above it passed. A red scan means this stage never starts.

Green output

+ /opt/dependency-check/bin/dependency-check.sh --project badge-api ... --nvdApiKey ****
[INFO] Checking for updates
[INFO] Analysis Complete (5 seconds)
[Pipeline] archiveArtifacts
Archiving artifacts
[Pipeline] stage (Live (lab))
Finished: SUCCESS

Expected result. Report archived, key masked as ****, gate passed.

Example 2: Java with the Maven plugin and a real red build

Stack. Java 17, Maven plugin

Goal. Java with the Maven plugin and a real red build.

pom.xml (plugin)

<plugin>
  <groupId>org.owasp</groupId>
  <artifactId>dependency-check-maven</artifactId>
  <version>10.0.3</version>
  <configuration>
    <failBuildOnCVSS>7</failBuildOnCVSS>
    <formats><format>HTML</format><format>JSON</format></formats>
    <suppressionFiles><suppressionFile>dc-suppressions.xml</suppressionFile></suppressionFiles>
    <nvdApiKeyEnvironmentVariable>NVD_API_KEY</nvdApiKeyEnvironmentVariable>
  </configuration>
</plugin>

pom.xml (old library on purpose)

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.8</version>
</dependency>

Command

mvn -B org.owasp:dependency-check-maven:check

What each line does

  • <failBuildOnCVSS>7</failBuildOnCVSS> — Maven fails when any library scores 7+.
  • <nvdApiKeyEnvironmentVariable> — Reads the key from an environment variable, never from the pom.
  • jackson-databind 2.9.8 — An old version with many known CRITICAL CVEs, to see red.
  • <suppressionFile> — Loads the false-positive file from Example 3.

Green output

[ERROR] One or more dependencies were identified with vulnerabilities that have a CVSS score greater than or equal to '7.0':
jackson-databind-2.9.8.jar: CVE-2019-12384(8.1), CVE-2019-14379(9.8), CVE-2020-36518(7.5) ...
[INFO] BUILD FAILURE

Expected result. Red, with the library and scores named. Update to jackson-databind 2.17.2 and it goes green.

Example 3: Python and a false positive, suppressed the right way

Stack. Python 3.11, requirements.txt

Goal. Python and a false positive, suppressed the right way.

dc-suppressions.xml

<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
  <suppress until="2026-12-31Z">
    <notes>False positive: CPE matched the "requests" CLI tool, not the Python library. SEC-151.</notes>
    <packageUrl regex="true">^pkg:pypi/requests@.*$</packageUrl>
    <cve>CVE-2014-1830</cve>
  </suppress>
</suppressions>

Command

dependency-check.sh --project badge-py --scan requirements.txt --enableExperimental --suppression dc-suppressions.xml --data /var/cache/odc --noupdate --failOnCVSS 7 --out reports

What each line does

  • --enableExperimental — The Python analyzer is marked experimental; this turns it on.
  • <suppress until="2026-12-31Z"> — The suppression expires, so someone must look again.
  • <notes> — Why it is safe to ignore, with a ticket number.
  • <packageUrl> + <cve> — Hides only that CVE on that package, nothing else.

Green output

[INFO] Analysis Complete (3 seconds)
[INFO] 1 vulnerability suppressed
exit=0

Expected result. Green, and the report shows the suppressed item in its own section, so auditors can still see it.

Verify: did it work?

  1. Count findings in JSON

    jq "[.dependencies[] | .vulnerabilities // [] | .[]] | length" reports/dependency-check-report.json
    

    What it does: Counts all CVEs found across libraries.

    Output

    0
    
  2. Top scores

    jq -r ".dependencies[] | select(.vulnerabilities) | .fileName" reports/dependency-check-report.json
    

    What it does: Lists libraries that have any CVE.

    Output

    (empty when clean)
    
  3. Publish in Jenkins

    dependencyCheckPublisher pattern: "reports/dependency-check-report.xml"
    

    What it does: With the OWASP Dependency-Check Jenkins plugin, this draws a trend chart on the job page.

    Output

    [DependencyCheck] Collecting results
    [DependencyCheck] Found 0 vulnerabilities
    

When it is red 1

[WARN] An NVD API Key was not provided - it is highly recommended to use one
[INFO] Downloading NVD data... (this may take 2+ hours)

Cause. No API key, so NVD throttles the download.

Fix, step by step

  1. Get the free key from NVD.
  2. Store it as lab-nvd-key and pass with --nvdApiKey "$NVD_API_KEY".
  3. Use a shared --data cache folder.

When it is red 2

[ERROR] Unable to obtain an exclusive lock on the H2 database to perform updates

Cause. Two builds update the same --data folder at the same time.

Fix, step by step

  1. Run updates only in one nightly job with --updateonly.
  2. In normal builds use --noupdate.
  3. Or use lock('odc-db') { ... } from the Lockable Resources plugin.

When it is red 3

Analysis Complete. 0 dependencies scanned.

Cause. You scanned the wrong folder, or node_modules is missing and the lock file is not found.

Fix, step by step

  1. Check the --scan path.
  2. Make sure package-lock.json, requirements.txt or pom.xml is in it.
  3. Rerun and check "Finished ... Analyzer" lines.

Cleanup

  1. Remove local reports

    rm -rf reports/
    

    What it does: Deletes local report files (Jenkins keeps archived copies).

    Output

    (no output)
    
  2. Keep the cache, drop the zip

    rm -f dependency-check-*-release.zip
    

    What it does: Removes the download; keep /var/cache/odc for speed.

    Output

    (no output)
    

Ravindra Bagale's Tip

NVD key credential madhe. Suppression la kaaran aani expiry date dyaa.

Practice tasks

Easy Get the NVD key

Why: Without it updates take hours.

What to do: Request the key and store it in Jenkins.

How:
  1. Request on the NVD site.
  2. Add Secret text lab-nvd-key.

Check: The credential exists.

Medium Nightly DB update job

Why: Builds must not fight over the DB.

What to do: Create a nightly pipeline that runs --updateonly.

How:
  1. triggers { cron('H 1 * * *') }
  2. Run with --data /var/cache/odc.

Check: Builds show "Skipping update" and run fast.

Medium Break with jackson 2.9.8

Why: See a real red report.

What to do: Use Example 2.

How:
  1. Add the old dependency.
  2. Run mvn dependency-check:check.

Check: BUILD FAILURE with CVE list.

Hard Write a suppression

Why: False positives happen; handle them honestly.

What to do: Suppress one false positive with notes and until date.

How:
  1. Find a CVE that does not apply.
  2. Write the XML.
  3. Rerun.

Check: Report lists it as suppressed.

Easy Run Dependency-Check by hand once

Why: Running a tool by hand first shows you what Jenkins will see.

What to do: Run Dependency-Check on your laptop against the Node badge app, before Jenkins.

How:
  1. Open a terminal in the badge-api folder.
  2. Run the Dependency-Check command from step-by-step.
  3. Read the summary line.

Check: You can say how many findings there are and what the exit code was (echo $?).

Medium Make Dependency-Check go red on purpose

Why: A gate you have never seen fail is a gate you do not trust.

What to do: Add one bad thing that Dependency-Check should catch and run the build.

How:
  1. Create a branch called break-scan.
  2. Add the bad change from the "When it is red" section.
  3. Push and watch the build.

Check: The scan stage is red and the Live (lab) stage is skipped.

Medium Archive the Dependency-Check report

Why: Reviewers and auditors need the report file, not only the console.

What to do: Save the report as a build artifact in Jenkins.

How:
  1. Write the report to reports/ in the scan command.
  2. Add post { always { archiveArtifacts artifacts: 'reports/**', allowEmptyArchive: true } }.
  3. Run the build and open the Artifacts link.

Check: The report file is downloadable from the build page.

Hard Explain Dependency-Check in 60 seconds

Why: Interviewers ask "what does this stage do and why".

What to do: Record yourself explaining the stage to a fresher.

How:
  1. Say the problem it solves.
  2. Say the command and the exit code rule.
  3. Say what you do when it is red.

Check: A friend can repeat back when the build should go red.

Homework: try at home

Try at home

Add jackson-databind 2.9.8 to the Java app, see the red build, then fix it by upgrading, and write down the before/after CVE count.

Recap

  • Dependency-Check maps libraries to CVEs from the NVD.
  • Gate with --failOnCVSS 7 (or failBuildOnCVSS in Maven).
  • Use an NVD API key from credentials and a shared data cache.
  • Update the DB nightly; use --noupdate in builds.
  • Suppressions need notes, narrow match and an expiry.

FAQ

Dependency-Check or Trivy fs?

Both find vulnerable libraries. Many teams use Dependency-Check for audit reports in Java, Trivy for speed.

Why so many false positives?

CPE matching by name is not perfect. Suppress carefully.

Does it scan node_modules?

Exclude it; scanning package-lock.json is enough and faster.

Can it run in Docker?

Yes, the owasp/dependency-check image, with the data folder mounted as a volume.

Which report for Jenkins plugin?

XML, used by dependencyCheckPublisher.

Interview questions

  1. What is SCA?

    Software Composition Analysis: finding known vulnerabilities and licenses in third-party dependencies. Dependency-Check is an SCA tool.

  2. How do you fail a build on vulnerable dependencies?

    Run Dependency-Check with --failOnCVSS 7 (or Maven failBuildOnCVSS) in a pipeline stage.

  3. How do you deal with false positives?

    A suppression file with a narrow match, reason and expiry, reviewed in code review.

  4. Why is the first run slow?

    It downloads the whole NVD; use an API key and cache, update nightly.

  5. What is a transitive dependency and why does it matter?

    A dependency of your dependency; most vulnerabilities hide there, and SCA tools check them too.

Quick quiz

Q1. What does --failOnCVSS 7 do?

Fails the scan if any CVE scores 7.0 or more.

Q2. Where is the NVD key kept?

Jenkins credential lab-nvd-key, used with withCredentials.

Q3. Why --noupdate in builds?

A nightly job updates the DB; builds stay fast and avoid lock errors.

Q4. What must a suppression have?

Notes with a reason, a narrow match, and an until date.

Q5. Name one CVSS band.

7.0-8.9 is HIGH.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards