Skip to content

OWASP Dependency Check

OWASP Dependency Check (ODC) scans project dependencies against the National Vulnerability Database (NVD) and detects known vulnerable libraries. It runs as Stage 6 in the DevSecOps pipeline, after Trivy dependency scanning, providing a second-opinion scan with a different vulnerability database.


Positioning in the DevSecOps Pipeline

Pipeline Stages
──────────────────────────────────────────────────────────────
Stage  1: Gitleaks       — Secret scanning
Stage  2: Build          — dotnet restore / npm install
Stage  3: SonarCloud     — SAST (code quality + security)
Stage  4: Trivy (fs)     — Dependency CVE scan
Stage  5: Trivy (config) — IaC misconfiguration scan
Stage  6: OWASP DC       — NVD-based dependency CVE scan  ◄──
Stage  7: (reserved)
Stage  8: Docker Build   — Multi-stage Dockerfile
Stage  9: Trivy (image)  — Container image CVE scan
Stage 10: Syft SBOM      — Software Bill of Materials
...
──────────────────────────────────────────────────────────────

Why Both Trivy and OWASP DC?

Trivy and OWASP DC use different vulnerability databases and detection methods. Trivy is faster and catches more container-layer issues. OWASP DC is deeper on Java/NuGet ecosystems and uses NVD as its authoritative source. Running both maximizes coverage with minimal false-negative risk.


Ecosystems Scanned

EcosystemFiles Analyzed
.NET / NuGet*.csproj, packages.lock.json
Node.js / npmpackage-lock.json, yarn.lock
Java / Mavenpom.xml, *.jar
Java / Gradlebuild.gradle, *.jar

OWASP DC downloads and parses dependency metadata then cross-references against NVD CVE records using CPE (Common Platform Enumeration) matching.


Pipeline Integration

Stage 6 pipeline task:

yaml
- stage: OwaspDependencyCheck
  displayName: 'Stage 6 - OWASP Dependency Check'
  dependsOn: TrivyIaC
  jobs:
    - job: OwaspDC
      pool:
        vmImage: 'ubuntu-latest'
      steps:
        - checkout: self

        - task: Bash@3
          displayName: 'Run OWASP Dependency Check'
          inputs:
            script: |
              mkdir -p $(Build.ArtifactStagingDirectory)/owasp-dc

              docker run --rm \
                -v $(Build.SourcesDirectory):/src \
                -v $(Build.ArtifactStagingDirectory)/owasp-dc:/report \
                -v $(Pipeline.Workspace)/.odc-data:/usr/share/dependency-check/data \
                owasp/dependency-check:latest \
                  --project "Microtec ERP" \
                  --scan /src \
                  --format HTML \
                  --format JSON \
                  --format SARIF \
                  --out /report \
                  --failOnCVSS $(owaspDcFailThreshold) \
                  --suppression /src/DevSecOps/config/owasp-suppressions.xml \
                  --enableExperimental \
                  --disableYarnAudit \
                  --log /report/owasp-dc.log

        - task: PublishBuildArtifacts@1
          condition: always()
          displayName: 'Publish OWASP DC Report'
          inputs:
            pathToPublish: '$(Build.ArtifactStagingDirectory)/owasp-dc'
            artifactName: 'security-owasp-dc'

Failure Threshold Configuration

The pipeline uses the --failOnCVSS flag to block on high-severity findings:

VariableValueMeaning
owaspDcFailThreshold7Block on CVSS score ≥ 7.0 (HIGH and CRITICAL)

The threshold is defined in the mic-erp-{env}-vars variable group in Azure DevOps. It can be raised to 9 (CRITICAL only) during a grace period when remediating findings.

yaml
# Variable group setting
owaspDcFailThreshold: 7  # dev, stage, preprod, uat
owaspDcFailThreshold: 9  # production (CRITICAL only — blocks release)

Suppression File

Known false positives and accepted risks are recorded in the suppression file. This file is version-controlled and requires peer review before changes are merged.

Location: DevSecOps/config/owasp-suppressions.xml

xml
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">

  <!--
    CVE-2024-XXXXX: False positive — affects Node.js CLI tooling only.
    The affected package (X) is a dev dependency not included in the production bundle.
    Accepted by: M.Araby | Date: 2025-04-01 | Expires: 2025-10-01
    Ticket: ERP-5678
  -->
  <suppress until="2025-10-01Z">
    <notes>Dev-only dependency — not in production bundle. See ERP-5678.</notes>
    <cve>CVE-2024-XXXXX</cve>
    <packageUrl regex="true">^pkg:npm/affected-package@.*$</packageUrl>
  </suppress>

  <!--
    CVE-2024-YYYYY: Accepted risk — .NET runtime patched in dotnet 8.0.5+.
    Base image updated to 8.0.5 as of 2025-03-15. ODC has stale data.
    Accepted by: M.Araby | Date: 2025-03-15 | Expires: 2025-09-15
  -->
  <suppress until="2025-09-15Z">
    <notes>Resolved in .NET 8.0.5 base image update. Awaiting ODC DB refresh.</notes>
    <cve>CVE-2024-YYYYY</cve>
    <filePath regex="true">.*aspnetcore-runtime.*</filePath>
  </suppress>

</suppressions>

Suppression Entry Requirements

Every suppression entry must include:

FieldRequirement
until dateExpiry date — entry must be re-reviewed before this date
notesJustification: why is it suppressed?
CVE IDSpecific CVE, not wildcard
Package URL or file pathScope the suppression to the specific dependency
Accepted byName in a comment
Ticket referenceADO work item number

Expired Suppressions Block the Pipeline

OWASP Dependency Check automatically ignores suppression entries that have passed their until date. The finding will re-appear in the next scan. Monitor suppression expiry dates via Check-ExpiredSecrets.ps1 or a calendar reminder.


NVD Data Cache

OWASP DC downloads the NVD database on first run (~500 MB). Subsequent runs use the cached data mounted at /usr/share/dependency-check/data:

yaml
# Mount the NVD cache between pipeline runs (Pipeline.Workspace persists on self-hosted agents)
-v $(Pipeline.Workspace)/.odc-data:/usr/share/dependency-check/data

On Microsoft-hosted agents (ephemeral), the cache is not preserved between runs. This adds ~3–5 minutes for the NVD data download. To mitigate:

  1. Use a self-hosted build agent with persistent workspace
  2. Or use the --noupdate flag with a pre-warmed cache artifact
yaml
# Alternative: download NVD data as a pipeline artifact
- task: DownloadPipelineArtifact@2
  inputs:
    source: 'specific'
    project: '$(System.TeamProject)'
    pipeline: 'owasp-dc-data-refresh'    # Weekly data refresh pipeline
    artifactName: 'nvd-data-cache'
    targetPath: '$(Pipeline.Workspace)/.odc-data'

Reading the Report

The HTML report (published as a pipeline artifact) includes:

SectionContent
SummaryTotal dependencies scanned, CVE count by severity
DependenciesEach dependency with its identified CPE and matched CVEs
VulnerabilitiesCVE detail: CVSS score, description, affected versions, fix version
SuppressedFindings that were suppressed with justification

To view the report:

  1. Go to the pipeline run in Azure DevOps
  2. Click Artifactssecurity-owasp-dc
  3. Download dependency-check-report.html
  4. Open in browser

Remediating Findings

When OWASP DC blocks the pipeline:

  1. Identify the vulnerable package from the HTML report (dependency name + CVE)
  2. Check for a fixed version in the CVE advisory or package release notes
  3. Update the package in .csproj or package.json
  4. If no fix is available:
    • Assess actual exploitability in the Microtec context
    • If non-exploitable (e.g., test-only dependency, affected code path not reachable): add a time-limited suppression with a ticket reference
    • If exploitable: escalate to security team; consider removing the dependency

Running Locally

bash
# Install via Docker (recommended)
docker run --rm \
  -v $(pwd):/src \
  -v ~/.odc-data:/usr/share/dependency-check/data \
  owasp/dependency-check:latest \
    --project "Microtec Local Scan" \
    --scan /src/Platforms \
    --format HTML \
    --out ./owasp-report \
    --suppression DevSecOps/config/owasp-suppressions.xml \
    --failOnCVSS 7

# View report
open owasp-report/dependency-check-report.html

Internal Documentation — Microtec Platform Team