Caution
VulnerabilityHub is currently pre-alpha. Every 0.x release, including
the planned v0.1.0, is a prerelease and may contain breaking changes. It is
not recommended for production use. Stable maintenance begins with v1.0.0.
Vulnerability management platform with automated scanning, ML-powered predictions, and comprehensive reporting.
- 🔍 Automated Vulnerability Scanning - Parse and analyze Greenbone/OpenVAS reports
- 🔄 Greenbone GMP Integration - Review target-to-institution imports and automatically synchronize completed reports
- 📊 Predictive Analytics - ML-based forecasting of vulnerability trends
- 📧 Smart Notifications - Magic link delivery with customizable templates
- 👥 Contact Management - Pluggable import system with conflict resolution
- 📈 Built-in Insights Overview - Native charts and remediation prioritization
- 🔐 Secure Access - JWT authentication with role-based permissions
For a production-style installation, download the deployment archive from the
desired GitHub Release.
It contains a docker-compose.release.yml pinned to the exact released image
digests, an environment example, checksums, image metadata, and upgrade
instructions. No source checkout or local image build is required.
Backend startup automatically widens scan_host_technologies.location_name to LONGTEXT on existing MariaDB installations, preserving complete host-technology location lists. The upgrade is idempotent, keeps existing values, and requires the application database user to have ALTER permission. Back up the database before upgrading; the first startup may take longer while this table is altered. Re-import reports that previously failed with a location-length error after deploying the updated backend.
The commands below start a development checkout:
# Clone repository
git clone https://github.com/bwInfoSec/VulnerabilityHub.git
cd VulnerabilityHub
mkdir secrets
# generate docker secrets
touch secrets/db_password.txt secrets/db_root_password.txt secrets/jwt_secret.txt
# Start services
docker compose up -d
# Or include development helpers such as MailHog and the local LDAP server
docker compose --profile dev up -d
# Access application
# http://localhostIf you want to include demo data for exploration or showcase purposes, run:
docker exec -it vulnerabilityhub-backend-1 python3 generate_demo_data.py
When the dev profile LDAP server is running, the demo script also creates demo
LDAP users and stores an enabled admin LDAP connection. The directory is
reachable from containers at ldap://ldap:389 and from the host at
ldap://localhost:1389; the default bind is
cn=admin,dc=example,dc=org / admin, and seeded LDAP users use
LdapUserPass123! unless DEMO_LDAP_USER_PASSWORD is set.
Upon first usage or database refresh, no user is available in the backend. Using the frontend you will be requested to setup an initial admin account which you can later on remove if need be.
By default, synchronized Greenbone reports notify only for the newest imported report generation of each task. In Application Settings > Email Automation, turn Only notify for the latest report per scan task on or off and click Save; no restart is required. Turning it off allows older reports under the normal notification, access, and retention rules. Different task IDs remain independent even when they share a target. When enabled, older generations stay skipped even if they were never delivered or a contact was assigned later; historical resend requests follow the same rule. Per-host and institution exports belonging to the newest report remain eligible. Reports without a known Greenbone task ID are not grouped by filename, target, or IP, to avoid suppressing unrelated scans.
Application Settings includes a search field matching names, descriptions, setting keys, and section names. Search for "latest report" to find this switch directly; filtering preserves unsaved changes.
- Getting Started - Installation and setup
- Architecture - System design and components
- User Guide - How to use the platform
- Development Guide - Contributing and development
- Import Greenbone XML reports
- Optionally connect to Greenbone GMP for reviewed target imports and scheduled XML/PDF/HTML report retrieval
- Track by severity, CVE, host, product
- Historical trend analysis
- Automated deduplication
- Multi-source import (CSV, Database, Scripts)
- Conflict resolution for manual changes
- Self-service profile management
- Change audit trail
- Magic link generation with configurable retention expiry
- Customizable email templates
- Access logging and monitoring
- Alert system for unaccessed reports
The Insights overview treats the latest XML scan day as the current source of truth. For a selected institution, current totals, breakdowns, top hosts, and quick wins are calculated only from that institution's latest scan date in the selected time range. For the complete overview across all institutions, the same widgets combine the latest XML scan activity for each institution individually.
Upload complete institution scans for accurate current-state reporting. Partial CIDR scans, single-host verification scans, or other incomplete uploads can make omitted findings disappear from the current Insights view because the latest scan XML day is considered authoritative for the affected institution. A complete clean XML scan with zero findings will therefore clear that institution from current finding totals.
Insights reflects uploaded XML scan data. If an institution has a high number of CVEs in its latest XML scan and you never upload a newer complete XML scan for that institution, the platform has no evidence that the findings were fixed. Rescan after remediation and upload the new XML, otherwise Insights, trends, and current totals can remain stale or misleading.
Yes, for now. Treat XML uploads as complete institution snapshots. The current Insights model uses the latest XML scan day as the source of truth, so partial CIDR scans, single-host verification scans, or other smaller XML uploads can replace the current view for an institution and make non-scanned hosts appear clean.
Yes. PDF and HTML visual reports may be either per-host reports or complete master visual reports. XML files are the structured source for analytics, matching, notifications, and access decisions. Visual reports are delivery artifacts and can be linked to one host in an XML or, after an explicit admin warning, to every host in the XML.
Unmatched or ambiguous visual reports do not send notifications. A visual report is delivered only when it is linked to exactly one XML context, or when an admin explicitly links it as a master visual for all hosts in the XML. Review pending visuals under Manage -> Disputes.
Filename patterns are how recurring scans of the same network are separated from
older or newer scan generations. Use stable names with a date, facility, and host
suffix where appropriate, for example 2026-02-01_campus_198.51.100.5.html for
a host visual and 2026-02-01_campus.xml for the master XML.
Yes. Old XML or visual reports can be uploaded later, but their filenames still need enough context for matching. Existing matched visual reports stay pinned to their original XML and are not moved automatically when a newer rescan is uploaded.
The upload is kept, but the system opens disputes for missing responsibility or institution mappings. Notifications are withheld where the responsible contact cannot be determined. Resolve these disputes before relying on delivery status.
Saving an institution is immediate, but report assignment refreshes run in the background for affected scans. This keeps the UI responsive while historical scan metadata and institution disputes are updated.
- Documentation: docs/
- Support policy: SUPPORT.md
- Contributing: CONTRIBUTING.md
- Upgrade policy: UPGRADING.md
- Issues: GitHub Issues
- Security reports: SECURITY.md
- Docker
- Docker Compose
- Node.js and npm (for frontend hot-reloading)
- Chromium browser for Playwright (
npm --prefix src/frontend/app exec playwright install chromium)
For a better frontend development experience with hot-reloading, follow these steps:
-
Launch Services: Run the following command from the project root to start the backend, database, and other services.
docker compose up -d
-
Stop the frontend container:
docker compose down frontend
-
Navigate to Frontend Directory:
cd frontend/app -
Install Dependencies:
npm install
-
Run the Dev Server:
npm run dev
The frontend will now be available at http://localhost:5173 (or another port specified by Vite) and will automatically reload when you make changes to the source code. The backend is already configured to run on hot-reload in its containerized form.
The default backend pytest run is the fast unit suite. It excludes tests marked db, so it does not need Docker or a live database:
python -m pytest src/backend/testsDB-backed backend integration tests run separately against MariaDB. The runner starts a fresh Docker Compose database, executes src/database/vulnerability_scanner.sql, runs only tests marked db, and removes the test stack afterwards:
scripts/e2e/run-backend.shSet BACKEND_E2E_SKIP_CLEANUP=1 to keep the database container and volume after a run for debugging.
The end-to-end smoke suite starts the backend stack in Docker dev mode, launches the Vite frontend, and verifies a broader admin flow: initial admin bootstrap, login success and failure handling, profile updates, password rotation, institution and contact-person management, XML upload, sent-report notification resend, retention reset, authorized report pickup, responsibility disputes, unauthorized access rejection, and cleanup.
Run it locally with:
npm --prefix src/frontend/app run test:e2e:localThe fresh-stack runner explicitly uses ENV=development, independent of your local .env. To verify bootstrap, profile updates, and password rotation with production CSRF protection enabled:
E2E_ENV=production bash scripts/e2e/run-local.sh --grep 'bootstraps the initial admin account|authenticates, updates the profile, and rotates the password'CI runs both the development suite and production auth checks through bash scripts/e2e/run-with-retry.sh. A failed run gets one retry with a freshly reset Docker stack; two failed attempts fail the pipeline. Local runs remain single-attempt unless you use this wrapper.
To watch the browser while the suite runs, use:
npm --prefix src/frontend/app run test:e2e:local:headedIf you already started the backend stack yourself, you can run only the browser suite with:
npm --prefix src/frontend/app run test:e2etest:e2e:local is the full fresh-stack entrypoint. test:e2e:local:headed does the same reset, but shows the browser live. test:e2e and test:e2e:headed assume the dev services are already running and that the e2e database has already been reset.
If you run only test:e2e against a manually started stack, the browser suite also expects MailHog to be reachable for email-link assertions. By default it checks http://127.0.0.1:8025, or you can override that with MAILHOG_UI_PORT / E2E_MAILHOG_PORT.