Skip to content

Repository files navigation

OpenVAS-Tracker

Vulnerability management dashboard that imports OpenVAS and OWASP ZAP scan results and tracks remediation through automated ticketing.

Screenshots

Dashboard Tickets Ticket Detail
Dashboard Tickets Ticket Detail

Features

  • OpenVAS Import: Webhook endpoint receives scan results automatically when scans complete, with original scan timestamps preserved from GMP reports
  • OWASP ZAP Import: Webhook endpoint for ZAP Traditional JSON Reports — one ticket per host per alert type, with every affected URL and parameter listed in the ticket detail
  • Multi-Scanner Architecture: Pluggable parser interface supports multiple scanner types with scan-type-scoped auto-resolve
  • Automatic Ticketing: New findings create tickets, missing findings auto-resolve, recurring findings reopen
  • Flapping Protection: Configurable threshold (default 3) of consecutive scan misses before auto-resolve — prevents noisy ticket churn from intermittent scan results, with visible pending_resolution intermediate status
  • Scope-aware Auto-resolve: Importing a scan only auto-resolves tickets for hosts that were in that scan's scope — other subnets are unaffected
  • Ticket Lifecycle: open → pending_resolution → fixed / risk_accepted / false_positive, with full activity audit trail
  • Risk Acceptance with Expiry: Risk-accepted tickets auto-reopen after expiry date (checked during imports)
  • Auto-Accept Rules: Define rules (by CVE or title, per host or globally) to automatically accept known risks on future imports — configurable from any ticket
  • Scan Comparison: Side-by-side diff of two scans, classifying each finding as new, rediscovered, pending-fix, fixed, risk-accepted, host-not-scanned, or unchanged. Coverage-aware (a host absent from one scan is flagged host_unscanned instead of falsely new/fixed) and flap-aware (a finding whose ticket predates the scan is not reported as new)
  • Bulk Actions: Select multiple tickets for batch status change or assignment
  • Dashboard: Open ticket counts by priority, scan source distribution pie chart (OpenVAS vs ZAP), 30-day trend chart, "My Tickets" and "Unassigned" quick filters
  • Greenbone Feed Freshness: The GMP fetch script reports feed versions after each import; Dashboard and Settings show whether NVT/SCAP/CERT feeds are current
  • CVE & CWE References: NVD, MITRE, and Google links on tickets with CVE; CWE links for ZAP findings; title-based search for tickets without
  • Also Affected: See which other hosts have the same vulnerability — click any affected host to filter tickets by that host
  • DNS Hostname Resolution: Automatic PTR lookup with 48h cache and 3s per-lookup timeout, normalized (UPPERCASE.domain.lowercase), runs async after import so a misbehaving DNS can never stall an import
  • LDAP / Active Directory: Optional AD authentication with group-based access control
  • Admin + LDAP Auth: Built-in admin user plus optional LDAP for team access, login by username
  • Settings UI: Edit common configuration keys (.env file) from the browser, test LDAP connection (changes need a service restart)
  • Filterable & Sortable Tables: Column sorting, multi-filter (priority, status, host, scan source, assignee), full-text search across all columns, searchable host filter with hostname autocomplete, default filter on open tickets
  • Report Generation: HTML, PDF, Excel, Markdown — technical, executive, compliance, comparison, and trend report types
  • Teams & Collaboration (API only): Create teams with member roles, invite users, assign tickets to teams
  • Assets Management (API only): Automatic asset inventory — hostname, IP, MAC, OS, open ports, services, risk score
  • Targets Management (API only): Define and manage scan targets/scopes
  • Notifications (API only, dormant): Endpoints for listing and marking notifications exist, but nothing currently generates them and no UI consumes them
  • Audit Logging (API only): Audit trail endpoint for actions logged by the backend services
  • Global Search (API only): Search across tickets, vulnerabilities, and hosts
  • Embedded React SPA: Single binary, no separate frontend deploy

Architecture

sequenceDiagram
    participant OV as OpenVAS (GVM)
    participant ZAP as OWASP ZAP
    participant TR as OpenVAS-Tracker
    participant AD as Active Directory
    participant DB as MariaDB
    participant UI as React Dashboard

    Note over OV: Network scan completes
    OV->>TR: HTTP GET /api/import/openvas?api_key=...
    TR->>OV: GMP Socket: fetch latest report
    OV-->>TR: XML report
    TR->>DB: Create scan + vulnerabilities + tickets
    TR->>DB: Upsert Greenbone feed versions

    Note over ZAP: Web app scan completes
    ZAP->>TR: POST /api/import/zap (JSON report)
    TR->>DB: Create scan + vulnerabilities + tickets

    TR->>DB: Check risk accept rules → auto-accept matches
    TR->>DB: Auto-fix/reopen tickets (scoped by scanner type)
    TR->>DB: Commit

    Note over UI: User logs in
    UI->>TR: POST /api/auth/login (username + password)
    alt Admin user
        TR->>TR: Check OT_ADMIN_PASSWORD
    else LDAP user
        TR->>AD: Bind + group check
    end
    TR-->>UI: JWT token
Loading

Quick Start with Docker

docker compose up -d

The UI is at http://localhost:8080. Login: username admin, password admin.

The compose file ships hardcoded local-dev credentials in docker-compose.yml (environment: block — it does not read .env). For anything beyond a local test, edit OT_JWT_SECRET, OT_ADMIN_PASSWORD, and OT_IMPORT_APIKEY there. Note: the Docker database is named openvas_tracker (underscore); the bare-metal default DSN uses openvas-tracker (hyphen).

Quick Start without Docker

# 1. Create database (migrations auto-apply on first app start)
mysql -e "CREATE DATABASE \`openvas-tracker\` CHARACTER SET utf8mb4;"

# 2. Configure
cat > .env << EOF
OT_DATABASE_DSN=root@tcp(localhost:3306)/openvas-tracker?parseTime=true
OT_JWT_SECRET=$(openssl rand -hex 32)
OT_IMPORT_APIKEY=$(openssl rand -hex 32)
OT_ADMIN_PASSWORD=your-admin-password
EOF

# 3. Build and run
make build && ./bin/openvas-tracker

Configuration

All config via .env file (or process environment / systemd EnvironmentFile=). Common keys editable from the Settings page in the UI (service restart required for changes to take effect).

Variable Default Purpose
OT_SERVER_HOST 0.0.0.0 HTTP listen address
OT_SERVER_PORT 8080 HTTP listen port
OT_DATABASE_DSN ...@tcp(localhost:3306)/openvas-tracker?parseTime=true MariaDB DSN
OT_DATABASE_MAXCONNS / OT_DATABASE_MINCONNS 25 / 5 DB connection pool size
OT_JWT_SECRET (none — required) JWT signing key (min 32 chars)
OT_JWT_EXPIREHOURS 24 Login token lifetime
OT_IMPORT_APIKEY (empty) API key for import webhook (min 32 chars). If unset, all import endpoints are disabled
OT_ADMIN_PASSWORD (empty) Admin user password
OT_GMP_USER admin Greenbone user used by the fetch script when GET /api/import/openvas is triggered
OT_GMP_PASSWORD (empty) Greenbone password for the fetch script
OT_AUTORESOLVE_THRESHOLD 3 Consecutive scans without finding before auto-resolve
OT_LDAP_URL (empty) LDAP server URL
OT_LDAP_BASE_DN (empty) LDAP search base DN
OT_LDAP_BIND_DN (empty) LDAP service account DN
OT_LDAP_BIND_PASSWORD (empty) LDAP service account password
OT_LDAP_GROUP_DN (empty) Required AD group for access
OT_LDAP_USER_FILTER (sAMAccountName=%s) LDAP user search filter
OT_LDAP_INSECURE_SKIP_VERIFY false Skip TLS certificate verification for ldaps:// (needed with internal CAs)
OT_BUGREPORT_URL (empty) Optional bug-report widget URL (origin is whitelisted in the CSP at startup)

Authentication

  1. Admin: Username admin + OT_ADMIN_PASSWORD → always available
  2. LDAP: Bind against Active Directory, verify group membership → if configured
  3. DB fallback: Existing database users (matched by email first, then username; must be active) → for backwards compatibility

No self-registration. LDAP users auto-created in DB on first login and also when the user list is loaded (Settings → Users), so they can be assigned to tickets before their first login.

Rate limits: 60 requests/min/IP on /api/auth, 500/min/IP globally.

OpenVAS Setup

  1. Set OT_IMPORT_APIKEY, OT_GMP_USER, and OT_GMP_PASSWORD in the env file the fetch script reads — /etc/openvas-tracker/env on a systemd install (override the path with OT_ENV_FILE). Without OT_IMPORT_APIKEY the import endpoints don't exist (404)
  2. In GSA: Configuration → Alerts → New Alert → HTTP Get → http://<host>:8080/api/import/openvas?api_key=<key>
  3. Attach alert to scan task

When the alert fires, the tracker runs sudo /usr/local/bin/openvas-tracker-fetch-latest, which speaks GMP directly to the local Greenbone Unix socket, downloads the newest report, POSTs it back to itself, and also reports the Greenbone feed versions. The script and its sudoers rule are installed by deploy/install.sh (they are not part of the .deb package). The script needs read access to the gvmd socket — by default it expects the Greenbone CE Docker volume path; override with OT_GMP_SOCKET when running the script manually (the sudo webhook path strips environment overrides).

ZAP Setup

ZAP scans are run externally — the tracker receives results via webhook. The same OT_IMPORT_APIKEY is used for both OpenVAS and ZAP imports.

Manual (ZAP Desktop)

  1. Run your scan in ZAP (Spider + Active Scan)
  2. Export report: Report → Generate Report → Traditional JSON
  3. Send to tracker:
curl -X POST https://your-server:8080/api/import/zap \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d @zap-report.json

Automated (ZAP Docker)

# Full scan (spider + active scan)
docker run --rm -v $(pwd):/zap/wrk ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py -t https://target-app.example.com -J zap-report.json

# Send results to tracker
curl -X POST https://your-server:8080/api/import/zap \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d @zap-report.json

ZAP Docker scan modes:

  • zap-baseline.py — Passive checks only (fast, safe for production)
  • zap-full-scan.py — Spider + active scan (thorough, sends attack payloads)
  • zap-api-scan.py — API scan against OpenAPI/Swagger definitions

Cron Example

#!/bin/bash
# /usr/local/bin/zap-scan-and-import.sh
TARGET="https://internal-app.example.com"
APIKEY="your-32-char-api-key"
REPORT="/tmp/zap-report.json"

docker run --rm --network host \
  -v /tmp:/zap/wrk ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py -t "$TARGET" -J zap-report.json

curl -s -X POST http://localhost:8080/api/import/zap \
  -H "X-API-Key: $APIKEY" \
  -H "Content-Type: application/json" \
  -d @"$REPORT"

rm -f "$REPORT"

How ZAP Findings Become Tickets

  • Each alert instance becomes a vulnerability record (URL, parameter, evidence, confidence)
  • Tickets are deduplicated per host + CVE, or per host + alert title when no CVE is present — one ticket per host per alert type; all affected URL + parameter pairs are listed in the ticket detail
  • Severity mapping: ZAP riskcode 3→high (CVSS 7.0), 2→medium (4.0), 1→low (2.0), 0→info (skipped)
  • Auto-resolve is scoped by scanner type — ZAP scans only affect ZAP tickets, never OpenVAS tickets

Ticket Lifecycle

Import finds new vulnerability     →  Ticket created (open)
Import matches risk accept rule    →  Ticket created (risk_accepted)
Import finds same vulnerability    →  Ticket updated (last_seen_at)
Import missing old vulnerability   →  Ticket pending_resolution (miss counter +1)
Consecutive misses reach threshold →  Ticket auto-fixed
Finding reappears while pending    →  Counter reset, ticket back to open
Import re-finds fixed vuln        →  Ticket reopened (open)
Import re-finds false_positive     →  Skipped (never reopened)
Risk acceptance expires            →  Ticket auto-reopened (on next import)

Auto-Accept Rules

Rules automatically set matching tickets to risk_accepted during import. Created from any ticket's detail page with scope "this host only" or "all hosts". Managed via the Auto-Accept Rules page, which also has a "Refresh Tickets" button to re-apply all rules to existing open tickets.

Matching by: CVE ID (if available) or vulnerability title. Optional expiry date.

API

Method Path Description
POST /api/auth/login Login (username + password)
POST /api/import/openvas Import OpenVAS XML (API-Key)
GET /api/import/openvas Trigger GMP fetch (API-Key)
POST /api/import/zap Import ZAP JSON report (API-Key)
POST /api/import/feeds Import Greenbone feed versions XML (API-Key)
GET /api/feeds Greenbone feed version status
GET /api/hosts Host summaries
GET /api/hosts/:host/vulnerabilities Vulnerabilities for a host
GET /api/hosts/:host/tickets Tickets for a host
GET /api/scans List scans
GET /api/scans/diff?old=X&new=Y Compare two scans
GET /api/scans/:id Scan detail
GET /api/scans/:id/vulnerabilities Vulnerabilities of a scan
GET /api/tickets List all tickets
POST /api/tickets Create ticket manually
POST /api/tickets/bulk Bulk status/assign
GET /api/tickets/:id Ticket detail
PATCH /api/tickets/:id/status Change status
PATCH /api/tickets/:id/assign Assign to user
POST /api/tickets/:id/risk-rule Create auto-accept rule from ticket
POST/GET /api/tickets/:id/comments Notes
GET /api/tickets/:id/activity Activity log
GET /api/tickets/:id/also-affected Other affected hosts
GET /api/dashboard Priority counts + ticket stats
GET /api/dashboard/trend 30-day open ticket trend
GET /api/settings/setup Setup guide
GET /api/settings/users User list (local + LDAP)
GET/PUT /api/settings/env Read/write .env config
PUT /api/settings/env/batch Batch update config
POST /api/settings/ldap/test Test LDAP connection
GET /api/settings/risk-rules List auto-accept rules
POST /api/settings/risk-rules/apply Re-apply rules to existing open tickets
DELETE /api/settings/risk-rules/:id Delete rule
GET /api/vulnerabilities List vulnerabilities
GET /api/vulnerabilities/:id Vulnerability detail
GET /api/vulnerabilities/:id/affected-urls All URLs affected by a finding
PATCH /api/vulnerabilities/:id/status Update vulnerability status
GET /api/search?q= Global search
GET /api/assets List assets
GET /api/assets/:id Asset detail
DELETE /api/assets/:id Delete asset
GET /api/targets List targets
POST /api/targets Create target
GET /api/targets/:id Target detail
DELETE /api/targets/:id Delete target
GET /api/teams List teams
POST /api/teams Create team
GET /api/teams/:id Team detail
GET/POST /api/teams/:id/members List/add members
POST /api/teams/:id/invite Invite user
DELETE /api/teams/:id Delete team
GET /api/notifications List notifications
GET /api/notifications/unread Unread count
PUT /api/notifications/:id/read Mark one read
PUT /api/notifications/read-all Mark all read
GET /api/audit Audit log
POST /api/reports Generate report (returns the file)
GET /api/reports List own reports
GET /api/reports/:id Report metadata + base64 file data (JSON)
GET /ws WebSocket connect (JWT via ?token=; reserved for future push)
GET /api/health Health check

Import endpoints (/api/import/*) only exist when OT_IMPORT_APIKEY is configured.

Tech Stack

  • Backend: Go 1.26, Echo v4, MariaDB, golang-jwt, bcrypt, godotenv, go-ldap
  • Frontend: React 19, TypeScript, Vite, Tailwind CSS, TanStack Query, react-router, Recharts, Zustand
  • Deploy: Docker Compose or systemd (Debian). Database migrations auto-applied on startup

Donate

If you find this project useful, consider supporting development:

XMR (Monero):

89fMD41wm8n88tgVj836qf3m16odqRjBhLti8dmVbvgsYAuEpTGfHBL7zNW8hingxQJNLWXfP3c2tgyyUMxYBiqHVYWR2rU

License

GPL v3

About

Vulnerability management dashboard for OpenVAS/Greenbone — automated ticketing, scan comparison, LDAP auth, risk acceptance rules. Single Go binary with embedded React UI.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages