tutorial

Monitoring Bomber (SBOM Vulnerability Scanner) with Vigilmon

Bomber is a fast SBOM vulnerability scanner that ingests CycloneDX or SPDX SBOMs and reports known CVEs from multiple vulnerability databases — but scan job failures, database update lapses, and missed critical CVEs are silent without external monitoring. Here's how to monitor Bomber scan availability, CVE database freshness, scan latency, and critical-finding alerting with Vigilmon.

Bomber is a lightweight, fast SBOM vulnerability scanner designed to consume CycloneDX or SPDX software bill of materials files and query multiple vulnerability databases — OSV, GHSA, NVD, and others — to surface known CVEs in your software components. It is commonly embedded in CI/CD pipelines as a quality gate between SBOM generation and artifact promotion: if a critical CVE is found, the pipeline fails and the release is blocked. When Bomber itself fails silently — crashes, hangs on a malformed SBOM, cannot reach its vulnerability database provider, or reports zero vulnerabilities because the database is stale — your quality gate disappears without triggering any CI failure flag, and vulnerable artifacts ship undetected. Vigilmon gives you external monitoring for Bomber process availability, vulnerability database freshness, scan completion rates, critical-CVE alerting latency, and database provider reachability so you know when your SBOM scanning gate is no longer protecting you.

What You'll Set Up

  • Bomber binary availability and version health
  • Vulnerability database provider reachability (OSV, GHSA, NVD)
  • Scan completion rate monitoring in CI pipelines
  • Database freshness tracking to catch stale CVE data
  • Critical-CVE alert delivery verification

Prerequisites

  • Bomber installed: go install github.com/devops-kung-fu/bomber@latest or the binary from releases
  • CycloneDX or SPDX SBOMs being generated in your pipeline (e.g., via Syft or cdxgen)
  • Access to CI pipeline logs or a webhook endpoint for scan results
  • A free Vigilmon account

Step 1: Monitor Bomber Binary Availability

Bomber is typically deployed as a single statically-linked binary or a container image layer. In containerized CI environments it is often pulled at job start; in persistent runner environments it lives in /usr/local/bin. Either way, a broken binary path, a failed container pull, or a version incompatibility with the SBOM schema version will cause the scan step to exit non-zero — but pipeline configurations that treat the scan as a non-blocking advisory step will swallow that error and proceed. Monitor the binary's basic availability on every runner:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to 15 minutes.
  3. Copy the heartbeat URL (e.g., https://vigilmon.online/heartbeat/abc123).
#!/bin/bash
# /usr/local/bin/bomber-health-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
BOMBER_BIN="${BOMBER_BIN:-bomber}"

# Check binary is present and executable
if ! command -v "$BOMBER_BIN" &>/dev/null; then
  echo "bomber binary not found in PATH"
  exit 1
fi

# Check it responds to version query
VERSION=$("$BOMBER_BIN" version 2>&1 | grep -E "^bomber|version" | head -1)
if [ -z "$VERSION" ]; then
  # Some bomber versions use --version flag
  VERSION=$("$BOMBER_BIN" --version 2>&1 | head -1)
fi

if [ -z "$VERSION" ]; then
  echo "bomber binary exists but produced no version output — may be corrupted"
  exit 1
fi

echo "Bomber OK: $VERSION"
curl -s "$HEARTBEAT_URL"
chmod +x /usr/local/bin/bomber-health-check.sh
(crontab -l 2>/dev/null; echo "*/15 * * * * /usr/local/bin/bomber-health-check.sh >> /var/log/bomber-health.log 2>&1") | crontab -

For containerized runners, build a minimal test stage in your pipeline that runs bomber version before the scan stage — if it fails, the scan stage never runs, making the failure explicit rather than silent.


Step 2: Monitor Vulnerability Database Provider Reachability

Bomber queries external vulnerability databases — OSV (api.osv.dev), the GitHub Advisory Database via GraphQL (api.github.com), and optionally NVD (services.nvd.nist.gov). If any of these providers are unreachable during a scan, Bomber may either skip that source silently or exit with an error depending on the --provider flag and configuration. A scan that queries only one of three providers due to a network issue provides far weaker coverage than intended. Monitor all providers your deployment uses:

#!/bin/bash
# /usr/local/bin/bomber-providers-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
TIMEOUT=10
FAILED=0

# Check OSV API
OSV_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "https://api.osv.dev/v1/query" \
  -H "Content-Type: application/json" \
  -d '{"package":{"name":"lodash","ecosystem":"npm"},"version":"4.17.20"}')

if [ "$OSV_CODE" = "200" ]; then
  echo "OSV API: OK ($OSV_CODE)"
else
  echo "OSV API: FAILED ($OSV_CODE)"
  FAILED=1
fi

# Check GitHub Advisory Database (GraphQL endpoint)
GHSA_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "https://api.github.com/graphql" \
  -H "Authorization: bearer ${GITHUB_TOKEN:-}" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ securityAdvisories(first:1) { totalCount } }"}')

# 401 is acceptable here if no token — it means the endpoint is reachable
if [ "$GHSA_CODE" = "200" ] || [ "$GHSA_CODE" = "401" ]; then
  echo "GitHub Advisory API: OK ($GHSA_CODE)"
else
  echo "GitHub Advisory API: FAILED ($GHSA_CODE)"
  FAILED=1
fi

# Check NVD API (if using NVD provider)
NVD_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "https://services.nvd.nist.gov/rest/json/cves/2.0?resultsPerPage=1")

if [ "$NVD_CODE" = "200" ]; then
  echo "NVD API: OK ($NVD_CODE)"
else
  echo "NVD API: DEGRADED ($NVD_CODE) — NVD has known reliability issues; alert if persistent"
  # NVD is frequently slow/unavailable; don't fail on first check
fi

if [ "$FAILED" -eq 0 ]; then
  curl -s "$HEARTBEAT_URL"
else
  exit 1
fi

Set the Vigilmon heartbeat to 10 minutes. NVD in particular has a history of API rate limiting and availability issues — configure Bomber to use OSV and GHSA as primary providers and treat NVD as supplemental so provider unavailability does not silently degrade your scan coverage.


Step 3: Monitor Scan Completion in CI Pipelines

Bomber scans should complete within a predictable time window — a scan that hangs waiting on a slow API response, that crashes on a malformed SBOM, or that is killed by a CI timeout will cause the pipeline to proceed without vulnerability data. Monitor scan completion by pinging a heartbeat at the end of each successful scan:

#!/bin/bash
# /usr/local/bin/bomber-scan-and-report.sh
# Wraps bomber scan with monitoring; use this script in CI instead of calling bomber directly

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
SBOM_PATH="${1:?Usage: $0 <sbom-path> [output-path]}"
OUTPUT_PATH="${2:-./bomber-report.json}"
BOMBER_BIN="${BOMBER_BIN:-bomber}"
PROVIDERS="${BOMBER_PROVIDERS:-osv,github}"
MAX_SCAN_MINUTES=10
TIMEOUT=$(( MAX_SCAN_MINUTES * 60 ))

echo "Starting Bomber scan: $SBOM_PATH"
START_TIME=$(date +%s)

# Run bomber with a timeout to prevent hangs
SCAN_OUTPUT=$(timeout "$TIMEOUT" "$BOMBER_BIN" scan \
  --providers "$PROVIDERS" \
  --format json \
  --output "$OUTPUT_PATH" \
  "$SBOM_PATH" 2>&1)
SCAN_EXIT=$?

END_TIME=$(date +%s)
DURATION=$(( END_TIME - START_TIME ))

if [ "$SCAN_EXIT" -eq 124 ]; then
  echo "Bomber scan TIMED OUT after ${MAX_SCAN_MINUTES} minutes on $SBOM_PATH"
  exit 1
elif [ "$SCAN_EXIT" -ne 0 ] && [ "$SCAN_EXIT" -ne 1 ]; then
  # Exit code 1 from bomber means vulnerabilities found (not an error)
  # Any other non-zero exit is a genuine scan failure
  echo "Bomber scan FAILED (exit $SCAN_EXIT) on $SBOM_PATH:"
  echo "$SCAN_OUTPUT"
  exit 1
fi

# Verify output file was written and is valid JSON
if [ ! -s "$OUTPUT_PATH" ]; then
  echo "Bomber produced no output file at $OUTPUT_PATH"
  exit 1
fi

VULN_COUNT=$(python3 -c "
import json, sys
with open('$OUTPUT_PATH') as f:
    data = json.load(f)
packages = data.get('packages', [])
total = sum(len(p.get('vulnerabilities', [])) for p in packages)
print(total)
" 2>/dev/null || echo unknown)

echo "Bomber scan OK: ${DURATION}s — $VULN_COUNT vulnerabilities found in $SBOM_PATH"
curl -s "$HEARTBEAT_URL"

Set the Vigilmon heartbeat to 35 minutes if your CI runs hourly. A missed heartbeat means either no build ran (check your CI schedule) or the scan step crashed or timed out.


Step 4: Track Database Freshness

Vulnerability databases publish new CVEs continuously; a Bomber installation that caches vulnerability data locally or queries a stale database mirror will miss recent CVEs. Track how recently Bomber's providers were updated relative to published CVE data:

#!/bin/bash
# /usr/local/bin/bomber-freshness-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/jkl012"
MAX_DB_AGE_HOURS=24
TIMEOUT=10

# Query OSV for recently-updated advisories and check if our local scan
# would detect a known recent CVE. Use a well-known, recently-updated package.
# This test uses a package with known CVEs to verify the database returns them.

TEST_ECOSYSTEM="npm"
TEST_PACKAGE="lodash"
TEST_VERSION="4.17.20"   # Known-vulnerable version

OSV_RESPONSE=$(curl -s \
  --max-time "$TIMEOUT" \
  "https://api.osv.dev/v1/query" \
  -H "Content-Type: application/json" \
  -d "{\"package\":{\"name\":\"$TEST_PACKAGE\",\"ecosystem\":\"$TEST_ECOSYSTEM\"},\"version\":\"$TEST_VERSION\"}")

VULN_COUNT=$(echo "$OSV_RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(len(data.get('vulns', [])))
" 2>/dev/null || echo 0)

if [ "$VULN_COUNT" -gt 0 ]; then
  echo "OSV freshness OK: $VULN_COUNT known CVEs returned for $TEST_PACKAGE@$TEST_VERSION"
  curl -s "$HEARTBEAT_URL"
else
  echo "OSV freshness SUSPECT: 0 CVEs returned for $TEST_PACKAGE@$TEST_VERSION (expected >0)"
  exit 1
fi

For environments using a private vulnerability database mirror or air-gapped NVD feeds, replace the OSV API call with a check against your mirror's last-updated timestamp:

# Check a locally-cached NVD feed's modification time
FEED_PATH="/var/lib/bomber/nvd-feed/nvdcve-1.1-recent.json.gz"
if [ -f "$FEED_PATH" ]; then
  FEED_AGE_HOURS=$(( ( $(date +%s) - $(stat -c %Y "$FEED_PATH") ) / 3600 ))
  if [ "$FEED_AGE_HOURS" -le "$MAX_DB_AGE_HOURS" ]; then
    echo "NVD feed age OK: ${FEED_AGE_HOURS}h old (max: ${MAX_DB_AGE_HOURS}h)"
    curl -s "$HEARTBEAT_URL"
  else
    echo "NVD feed STALE: ${FEED_AGE_HOURS}h old — update your feed sync job"
    exit 1
  fi
fi

Set the Vigilmon heartbeat to 30 minutes. A freshness check failure means your scans are running against out-of-date CVE data — new vulnerabilities published in the gap are invisible to your pipeline gate.


Step 5: Monitor Critical CVE Alert Delivery

When Bomber finds a critical CVE, the expectation is that an alert reaches your security team promptly — whether through a CI failure notification, a Slack alert, or a security dashboard. The time from CVE discovery to human awareness (alert delivery latency) is a security metric in itself. Verify the alert delivery path works end-to-end:

#!/bin/bash
# /usr/local/bin/bomber-alert-path-check.sh
# Run this as a synthetic test: inject a known-critical CVE and verify the alert fires

HEARTBEAT_URL="https://vigilmon.online/heartbeat/mno345"
ALERT_WEBHOOK="${SECURITY_ALERT_WEBHOOK:?Set SECURITY_ALERT_WEBHOOK env var}"
TEST_CVE_ID="CVE-2021-44228"   # Log4Shell — known critical, will always exist in databases
BOMBER_BIN="${BOMBER_BIN:-bomber}"

# Create a minimal CycloneDX SBOM containing a Log4j component (known-critical)
SYNTHETIC_SBOM=$(cat <<'SBOM'
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.4",
  "version": 1,
  "components": [
    {
      "type": "library",
      "name": "log4j-core",
      "group": "org.apache.logging.log4j",
      "version": "2.14.1",
      "purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1"
    }
  ]
}
SBOM
)

SBOM_FILE=$(mktemp --suffix=.json)
echo "$SYNTHETIC_SBOM" > "$SBOM_FILE"

# Run bomber against the synthetic SBOM
SCAN_OUTPUT=$(timeout 60 "$BOMBER_BIN" scan \
  --providers osv \
  --format json \
  "$SBOM_FILE" 2>&1)
SCAN_EXIT=$?

rm -f "$SBOM_FILE"

# Check that Log4Shell was detected
if echo "$SCAN_OUTPUT" | grep -qi "$TEST_CVE_ID" || \
   echo "$SCAN_OUTPUT" | python3 -c "
import sys, json
try:
    data = json.loads(sys.stdin.read().split('{', 1)[-1].rsplit('}', 1)[0].join(['{', '}']))
    packages = data.get('packages', [])
    vulns = [v for p in packages for v in p.get('vulnerabilities', [])]
    found = any('$TEST_CVE_ID' in str(v) for v in vulns)
    sys.exit(0 if found else 1)
except:
    sys.exit(1)
" 2>/dev/null; then
  echo "Bomber critical CVE detection OK: found $TEST_CVE_ID in synthetic SBOM"
  curl -s "$HEARTBEAT_URL"
else
  echo "Bomber critical CVE detection FAILED: $TEST_CVE_ID not detected in synthetic SBOM"
  exit 1
fi

Run this test every hour with a Vigilmon heartbeat at 75 minutes. A failure indicates either that the OSV database is not returning Log4j advisories (a freshness problem) or that bomber's scan logic has a provider-routing bug.


Step 6: Set Up Alert Channels

Configure Vigilmon to route Bomber monitoring alerts to your security and DevOps teams:

  1. Go to Alert Channels in Vigilmon.
  2. Add a Slack webhook to #security-scanning — scan failures mean vulnerable artifacts may be shipping.
  3. Add PagerDuty for the critical CVE detection monitor — a scanner that cannot detect Log4Shell is a security control failure.
  4. Add email notification for provider reachability and database freshness monitors.
  5. Set Consecutive failures before alert to 2 for provider reachability (brief API hiccups are common with NVD).

Include scan context in Slack alerts:

SBOM_PATH="frontend-sbom.cdx.json"
CRITICAL_COUNT=3
ALERT_MSG=":rotating_light: *Bomber found ${CRITICAL_COUNT} CRITICAL CVEs* in \`${SBOM_PATH}\`. Pipeline blocked. Review: https://ci.your-org.com/pipelines/${CI_PIPELINE_ID}"

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

Add maintenance windows during Bomber upgrades or database migrations:

curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "monitor_id": "BOMBER_MONITOR_ID",
    "duration_minutes": 10,
    "reason": "Bomber binary upgrade and database re-sync"
  }'

Summary

| Monitor | Target | What It Catches | |---|---|---| | Cron heartbeat (binary health) | bomber version | Missing binary, corrupted install | | Cron heartbeat (provider reachability) | OSV, GHSA, NVD APIs | Database provider outage, network block | | Cron heartbeat (scan completion) | Per-pipeline scan wrapper | Scan hangs, malformed SBOM crashes, timeouts | | Cron heartbeat (database freshness) | OSV known-CVE probe | Stale local mirror, feed sync failure | | Cron heartbeat (alert delivery) | Synthetic Log4Shell SBOM | CVE detection regression, broken alert path |

Bomber's failure mode is false confidence — when the scanner crashes or cannot reach its databases, the CI pipeline may still report success (especially if the scan step is advisory rather than blocking), and your team assumes components are clean when they haven't been checked. Vigilmon's external monitoring turns that invisible failure into an immediate alert: you know within minutes when your SBOM vulnerability scanning gate is no longer functioning.

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 →