tutorial

Monitoring OWASP Dependency-Track with Vigilmon

OWASP Dependency-Track is a continuous SBOM analysis platform that identifies component vulnerabilities, policy violations, and license risk across software portfolios — but a crashed API server, a stalled vulnerability analyzer, or a database sync failure silently stops protecting your portfolio. Here's how to monitor Dependency-Track availability, analyzer health, API responsiveness, and policy evaluation with Vigilmon.

OWASP Dependency-Track is a continuous SBOM intelligence platform that ingests CycloneDX and SPDX software bill of materials files, continuously analyzes every component against NVD, OSS Index, GitHub Advisories, and VulnDB, evaluates configurable policy rules for license risk and prohibited components, and provides a portfolio-wide view of your software supply chain risk. It runs as a Java Spring Boot API server backed by a PostgreSQL or embedded H2 database, with a dedicated Vue.js frontend. When the Dependency-Track API server is down, SBOMs from CI pipelines queue up or fail to upload — your risk intelligence goes dark. When the internal vulnerability analyzer stalls on a backlog of BOM processing tasks, component risk scores stop updating even though the server appears healthy. When the NVD data feed ingestion job silently fails, the platform continues showing component risk from days or weeks ago. Vigilmon gives you external monitoring for Dependency-Track API availability, analyzer queue health, vulnerability data feed freshness, policy evaluation health, and database responsiveness so you catch platform degradation before your security team makes risk decisions on stale data.

What You'll Set Up

  • Dependency-Track API server availability and authentication health
  • Vulnerability analyzer queue depth and processing lag
  • NVD and OSS Index data feed freshness monitoring
  • Policy violation evaluation health checks
  • Database and storage health monitoring

Prerequisites

  • Dependency-Track 4.x or later (API Server + Frontend) deployed
  • API key with VIEW_PORTFOLIO and BOM_UPLOAD permissions for monitoring queries
  • Access to the /api/version and /api/v1/metrics/portfolio endpoints
  • A free Vigilmon account

Step 1: Monitor API Server Availability

The Dependency-Track API server is the central hub: CI pipelines upload SBOMs to it, the frontend queries it, and all vulnerability and policy data flows through it. When the JVM runs out of heap, the embedded H2 database file is locked, or a database migration fails on startup after an upgrade, the API server becomes unavailable and the entire platform stops functioning. Monitor availability with an HTTP check against the health endpoint:

  1. In Vigilmon, click Add MonitorHTTP.
  2. Set the URL to https://your-dependency-track.internal/api/version.
  3. Set Check interval to 1 minute.
  4. Set Expected status code to 200.
  5. Optionally set a Response body contains check for "version" to verify the response is a valid API response, not an error page.

For environments where the /api/version endpoint requires no authentication, this is the simplest possible uptime check. For authenticated setups, use a cron heartbeat with an API key:

#!/bin/bash
# /usr/local/bin/dependency-track-health-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
DT_URL="${DEPENDENCY_TRACK_URL:-https://your-dependency-track.internal}"
DT_API_KEY="${DEPENDENCY_TRACK_API_KEY:?Set DEPENDENCY_TRACK_API_KEY}"
TIMEOUT=15

# Check API health via authenticated endpoint
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  -H "X-Api-Key: $DT_API_KEY" \
  "${DT_URL}/api/v1/metrics/portfolio")

if [ "$HTTP_CODE" = "200" ]; then
  echo "Dependency-Track API healthy: HTTP $HTTP_CODE"
  curl -s "$HEARTBEAT_URL"
else
  echo "Dependency-Track API unhealthy: HTTP $HTTP_CODE"
  exit 1
fi
chmod +x /usr/local/bin/dependency-track-health-check.sh
(crontab -l 2>/dev/null; echo "*/2 * * * * /usr/local/bin/dependency-track-health-check.sh >> /var/log/dt-health.log 2>&1") | crontab -

Set the Vigilmon heartbeat to 5 minutes if using the cron approach. A 2xx response from /api/v1/metrics/portfolio proves the API server is up, the database is reachable, and authentication is working — catching the most common failure modes in a single check.


Step 2: Monitor the Vulnerability Analyzer Queue

Dependency-Track processes uploaded SBOMs through an internal task queue — when a BOM is uploaded, each component is enqueued for vulnerability analysis against configured data sources. If the internal analyzer threads stall (due to a JVM thread leak, a slow NVD API response holding a connection pool, or a high-cardinality BOM overwhelming the queue), the queue depth grows while the API server remains responsive. Components are shown in the UI without vulnerability data, and the Last BOM processed metric falls behind. Monitor the analyzer backlog via the portfolio metrics endpoint:

#!/bin/bash
# /usr/local/bin/dependency-track-analyzer-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
DT_URL="${DEPENDENCY_TRACK_URL:-https://your-dependency-track.internal}"
DT_API_KEY="${DEPENDENCY_TRACK_API_KEY:?Set DEPENDENCY_TRACK_API_KEY}"
MAX_PORTFOLIO_COMPONENTS_STALE=500   # Alert if more than 500 components have no vuln data
TIMEOUT=15

# Get portfolio-level vulnerability metrics
PORTFOLIO_METRICS=$(curl -s \
  --max-time "$TIMEOUT" \
  -H "X-Api-Key: $DT_API_KEY" \
  "${DT_URL}/api/v1/metrics/portfolio")

if [ -z "$PORTFOLIO_METRICS" ]; then
  echo "Failed to retrieve portfolio metrics"
  exit 1
fi

# Check if the metrics were last updated recently
LAST_OCCURRENCE=$(echo "$PORTFOLIO_METRICS" | python3 -c "
import sys, json
from datetime import datetime, timezone

data = json.load(sys.stdin)
last_occ = data.get('lastOccurrence')
if not last_occ:
    print(-1)
    sys.exit(0)

# Dependency-Track returns epoch milliseconds
ts = last_occ / 1000
now = datetime.now(timezone.utc).timestamp()
age_hours = (now - ts) / 3600
print(int(age_hours))
" 2>/dev/null || echo -1)

MAX_AGE_HOURS=2   # Portfolio metrics should update within 2 hours

if [ "$LAST_OCCURRENCE" -eq -1 ]; then
  echo "Could not parse lastOccurrence from portfolio metrics — analyzer may be stalled"
  exit 1
elif [ "$LAST_OCCURRENCE" -gt "$MAX_AGE_HOURS" ]; then
  echo "Portfolio metrics STALE: last updated ${LAST_OCCURRENCE}h ago (max: ${MAX_AGE_HOURS}h)"
  exit 1
else
  echo "Vulnerability analyzer OK: portfolio metrics ${LAST_OCCURRENCE}h old"
  curl -s "$HEARTBEAT_URL"
fi

Set the Vigilmon heartbeat to 15 minutes. Analyzer staleness that persists beyond the MAX_AGE_HOURS threshold indicates the internal Kafka-based task queue (in Dependency-Track 4.5+) or the legacy internal queue (pre-4.5) has stalled — restart the API server to clear the thread pool and re-queue pending analysis tasks.


Step 3: Monitor Vulnerability Data Feed Freshness

Dependency-Track's NVD data feed sync is a scheduled job that pulls NVD CVE JSON feeds and the OSS Index API to update its internal vulnerability database. If the NVD sync job fails (due to rate limiting, network issues, or a changed NVD feed URL after the NVD 2.0 API migration), the platform continues displaying vulnerability data — but it becomes progressively staler as new CVEs go undetected. Monitor feed freshness via the vulnerability database metadata endpoint:

#!/bin/bash
# /usr/local/bin/dependency-track-feed-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
DT_URL="${DEPENDENCY_TRACK_URL:-https://your-dependency-track.internal}"
DT_API_KEY="${DEPENDENCY_TRACK_API_KEY:?Set DEPENDENCY_TRACK_API_KEY}"
MAX_NVD_AGE_HOURS=48    # NVD sync should run at least every 48 hours
TIMEOUT=15

# Get vulnerability database metadata
DB_META=$(curl -s \
  --max-time "$TIMEOUT" \
  -H "X-Api-Key: $DT_API_KEY" \
  "${DT_URL}/api/v1/vulnerability/source/NVD")

NVD_AGE=$(echo "$DB_META" | python3 -c "
import sys, json
from datetime import datetime, timezone

try:
    data = json.load(sys.stdin)
    # Different DT versions expose this differently
    last_modified = data.get('lastModified') or data.get('updated')
    if not last_modified:
        print(-1)
        sys.exit(0)

    if isinstance(last_modified, (int, float)):
        ts = last_modified / 1000
    else:
        # ISO string format
        dt = datetime.fromisoformat(str(last_modified).replace('Z', '+00:00'))
        ts = dt.timestamp()

    now = datetime.now(timezone.utc).timestamp()
    age_hours = int((now - ts) / 3600)
    print(age_hours)
except Exception as e:
    print(-1)
" 2>/dev/null || echo -1)

if [ "$NVD_AGE" -eq -1 ]; then
  # Fallback: check if NVD vulnerability count is non-zero (database initialized)
  VULN_COUNT=$(curl -s \
    --max-time "$TIMEOUT" \
    -H "X-Api-Key: $DT_API_KEY" \
    "${DT_URL}/api/v1/metrics/portfolio" | \
    python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('vulnerabilities', 0))" 2>/dev/null || echo 0)

  if [ "$VULN_COUNT" -gt 0 ]; then
    echo "NVD feed age unavailable via API — portfolio has $VULN_COUNT vulns (database not empty)"
    curl -s "$HEARTBEAT_URL"
  else
    echo "NVD feed unavailable and vulnerability count is 0 — database may not be initialized"
    exit 1
  fi
elif [ "$NVD_AGE" -le "$MAX_NVD_AGE_HOURS" ]; then
  echo "NVD feed OK: last updated ${NVD_AGE}h ago (max: ${MAX_NVD_AGE_HOURS}h)"
  curl -s "$HEARTBEAT_URL"
else
  echo "NVD feed STALE: last updated ${NVD_AGE}h ago (max: ${MAX_NVD_AGE_HOURS}h)"
  exit 1
fi

Set the Vigilmon heartbeat to 4 hours. NVD feed staleness is one of the most common and least visible Dependency-Track failure modes — the platform appears fully functional but is silently missing recently-published CVEs.


Step 4: Monitor SBOM Upload and Processing Health

CI pipelines upload SBOMs to Dependency-Track via the REST API (PUT /api/v1/bom) or the BOM upload token flow. If the upload endpoint returns errors — due to a payload size limit, an authentication change, or the internal BOM processing thread pool being exhausted — CI pipelines either fail (if configured as blocking) or silently skip the SBOM upload (if configured as advisory). Monitor upload health with a synthetic SBOM submission:

#!/bin/bash
# /usr/local/bin/dependency-track-upload-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/jkl012"
DT_URL="${DEPENDENCY_TRACK_URL:-https://your-dependency-track.internal}"
DT_API_KEY="${DEPENDENCY_TRACK_API_KEY:?Set DEPENDENCY_TRACK_API_KEY}"
TEST_PROJECT_NAME="vigilmon-health-check"
TEST_PROJECT_VERSION="0.0.1"
TIMEOUT=30

# Create a minimal CycloneDX 1.4 SBOM for the health check project
SYNTHETIC_BOM=$(python3 -c "
import base64, json

bom = {
    'bomFormat': 'CycloneDX',
    'specVersion': '1.4',
    'version': 1,
    'metadata': {
        'component': {
            'type': 'application',
            'name': 'vigilmon-health-check',
            'version': '0.0.1'
        }
    },
    'components': [
        {
            'type': 'library',
            'name': 'test-component',
            'version': '1.0.0',
            'purl': 'pkg:generic/test-component@1.0.0'
        }
    ]
}

print(base64.b64encode(json.dumps(bom).encode()).decode())
")

# Submit the BOM
RESPONSE=$(curl -s -w "\n%{http_code}" \
  --max-time "$TIMEOUT" \
  -X PUT \
  -H "X-Api-Key: $DT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"projectName\": \"$TEST_PROJECT_NAME\",
    \"projectVersion\": \"$TEST_PROJECT_VERSION\",
    \"autoCreate\": true,
    \"bom\": \"$SYNTHETIC_BOM\"
  }" \
  "${DT_URL}/api/v1/bom")

HTTP_CODE=$(echo "$RESPONSE" | tail -1)
RESPONSE_BODY=$(echo "$RESPONSE" | head -n -1)

if [ "$HTTP_CODE" = "200" ]; then
  TOKEN=$(echo "$RESPONSE_BODY" | python3 -c "import sys,json; print(json.load(sys.stdin).get('token',''))" 2>/dev/null)
  echo "SBOM upload OK: HTTP $HTTP_CODE, processing token: $TOKEN"
  curl -s "$HEARTBEAT_URL"
else
  echo "SBOM upload FAILED: HTTP $HTTP_CODE"
  echo "$RESPONSE_BODY"
  exit 1
fi

Set the Vigilmon heartbeat to 15 minutes. A successful upload returns a 200 with a processing token, confirming that the API server accepted the BOM and queued it for analysis. Pair this with the analyzer staleness check from Step 2 to confirm the BOM was also processed after upload.


Step 5: Monitor Policy Violation Evaluation

Dependency-Track's policy engine evaluates component license compliance, prohibited component lists, and vulnerability severity thresholds against every project in your portfolio. Policy violations are how Dependency-Track blocks deployments of non-compliant components. If the policy evaluation engine fails (due to a custom policy script error or a database lock during a concurrent BOM upload), violations stop being generated — projects appear policy-compliant when they may not be. Monitor policy evaluation via a known-violation probe:

#!/bin/bash
# /usr/local/bin/dependency-track-policy-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/mno345"
DT_URL="${DEPENDENCY_TRACK_URL:-https://your-dependency-track.internal}"
DT_API_KEY="${DEPENDENCY_TRACK_API_KEY:?Set DEPENDENCY_TRACK_API_KEY}"
TIMEOUT=15

# Get total policy violations across the portfolio
POLICY_RESP=$(curl -s \
  --max-time "$TIMEOUT" \
  -H "X-Api-Key: $DT_API_KEY" \
  "${DT_URL}/api/v1/metrics/portfolio")

POLICY_VIOLATIONS=$(echo "$POLICY_RESP" | python3 -c "
import sys, json
data = json.load(sys.stdin)
# policyViolationsTotal or policyViolations depending on DT version
total = data.get('policyViolationsTotal') or data.get('policyViolations', None)
print(total if total is not None else -1)
" 2>/dev/null || echo -1)

if [ "$POLICY_VIOLATIONS" = "-1" ]; then
  # Policy violations field missing — try the dedicated endpoint
  POLICY_COUNT=$(curl -s \
    --max-time "$TIMEOUT" \
    -H "X-Api-Key: $DT_API_KEY" \
    "${DT_URL}/api/v1/policy/violation?pageSize=1&pageNumber=1" | \
    python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    if isinstance(data, list):
        print(len(data))
    else:
        print(data.get('total', 0))
except:
    print(-1)
" 2>/dev/null || echo -1)

  if [ "$POLICY_COUNT" != "-1" ]; then
    echo "Policy engine OK: $POLICY_COUNT violations via direct endpoint"
    curl -s "$HEARTBEAT_URL"
  else
    echo "Policy evaluation API returned no data — engine may be degraded"
    exit 1
  fi
else
  echo "Policy engine OK: $POLICY_VIOLATIONS total violations in portfolio"
  curl -s "$HEARTBEAT_URL"
fi

Set the Vigilmon heartbeat to 15 minutes. A policy engine that returns null violation counts when you know your portfolio has policy violations indicates the evaluation job has stalled — trigger a manual re-evaluation via the Dependency-Track API and restart the API server if violations do not appear after 30 minutes.


Step 6: Set Up Alert Channels

Configure Vigilmon to route Dependency-Track alerts to your security and platform teams:

  1. Go to Alert Channels in Vigilmon.
  2. Add a Slack webhook to #security-platform — API outage means your entire SBOM intelligence platform is dark.
  3. Add PagerDuty for the API availability monitor — Dependency-Track downtime means CI pipelines cannot upload SBOMs and risk decisions are based on no data.
  4. Add email notification for feed freshness and policy evaluation monitors — degradation is serious but not immediate-response.
  5. Set Consecutive failures before alert to 2 for the analyzer queue monitor — brief processing delays during large BOM ingestion are normal.

Include platform context in Slack alerts:

DT_URL="https://your-dependency-track.internal"
ALERT_TYPE="NVD feed stale"
AGE_HOURS=52
ALERT_MSG=":warning: *Dependency-Track: ${ALERT_TYPE}* — NVD data is ${AGE_HOURS}h old. New CVEs published in the last 2 days may not appear in risk scores. Check the feed sync job in the DT admin console: ${DT_URL}/#/admin/vulnerabilities"

curl -X POST "$SECURITY_PLATFORM_WEBHOOK" \
  -H 'Content-type: application/json' \
  --data "{\"text\": \"$ALERT_MSG\"}"

Add maintenance windows during Dependency-Track upgrades:

curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "monitor_id": "DEPENDENCY_TRACK_MONITOR_ID",
    "duration_minutes": 30,
    "reason": "Dependency-Track upgrade and database migration"
  }'

# Stop DT, run the upgrade, restart
docker compose pull
docker compose down
docker compose up -d

Summary

| Monitor | Target | What It Catches | |---|---|---| | HTTP check | /api/v1/metrics/portfolio | API server down, database unreachable, auth broken | | Cron heartbeat (analyzer queue) | Portfolio metrics lastOccurrence | Analyzer thread stall, BOM processing backlog | | Cron heartbeat (NVD freshness) | NVD feed last-updated timestamp | Feed sync failure, NVD API rate limiting | | Cron heartbeat (SBOM upload) | Synthetic BOM PUT + 200 response | Upload endpoint broken, BOM processor exhausted | | Cron heartbeat (policy engine) | Policy violation count | Policy evaluation engine stalled, missing violations |

Dependency-Track's failure mode is the illusion of health — the API server responds, the dashboard loads, your portfolio looks monitored, but the vulnerability analyzer has stalled, the NVD feed is weeks old, and policy violations are no longer being generated. Teams make go/no-go deployment decisions on data that stopped updating days ago. Vigilmon's external monitoring catches each of these degradation modes independently so you know which layer failed and what to fix — rather than discovering the gap during a post-incident audit.

Start monitoring for free at vigilmon.online.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →