Files
vulncheck/PROJECT_OVERVIEW.md
T
vulncheck 0b71453c48 chore(release): drop personal attribution from comments and docstrings
Comments across the codebase credited one individual by role and, in places,
described that person's own machines: which SQL Server versions a host ran,
which devices were enrolled, what a particular dashboard showed, how many
findings sat open on which server. In a public repository that reads as a
profile of someone's unpatched estate.

The observations are why the code looks the way it does, so they stay. Every
CVE id, version, build number, count and date is preserved, as are the
verbatim quotes that motivated specific sort and filter rules — only the
attribution changes, to "field report", "observed", "a host". A local
variable in tests/test_autodesk_year.py was renamed for the same reason; its
value and every assertion around it are byte-identical.

PROJECT_OVERVIEW.md additionally loses a subtitle naming the kind of
organisation this was built for, and a support section pointing at an
internal team, both replaced with neutral wording.

Comments, docstrings and markdown prose only: 74 files, 200 lines, one-for-one
swaps. detect_changes reports 104 touched symbols and zero affected execution
flows, and all 55 test scripts pass. Nothing here needs re-testing.
2026-08-26 15:34:05 +02:00

14 KiB
Raw Blame History

TrueVuln — Project Overview

Self-hosted vulnerability management for small and mid-sized IT teams. Wazuh agents + Nessus scanner + CISA/ENISA/EPSS threat intel + CIS-Benchmark compliance + Unified Risk Score, all behind a single FastAPI + Next.js stack.

Stand: Mai 2026, dev-Branch, alembic head 022.


🎯 Summary

TrueVuln collects vulnerability findings from multiple scanners (Wazuh, Nessus), enriches them with several free public threat-intel sources, scores the result on a unified 0-100 risk scale, and surfaces them in a role-based web UI with SLA-tracking, mail notifications, compliance evidence (Wazuh SCA

  • CIS-Benchmark impact weights), and an LLM-backed remediation analysis.

Designed for internal small-to-mid IT teams (5-100 hosts). Single-server deployable via Docker Compose. Postgres-only persistence.


📁 Project Structure

vulnerability-dashboard/
├── app/                              # FastAPI backend
│   ├── routers/                      # HTTP API by resource
│   │   ├── auth.py, auth_admin.py
│   │   ├── auth_oidc.py, auth_saml.py
│   │   ├── vulnerabilities.py        # vulns, sync, enrichment, overrides
│   │   ├── nessus.py                 # Tenable Nessus
│   │   ├── assets.py, scans.py, policies.py, groups.py
│   │   ├── compliance.py             # SCA + URS endpoints
│   │   ├── notifications.py, reports.py, settings.py, audit.py
│   ├── services/                     # business logic, scheduler-reusable
│   │   ├── enrichment_service.py
│   │   ├── vuln_override_service.py  # 3-stage CVSS cascade
│   │   ├── override_jobs.py          # async job tracker
│   │   ├── nessus_sync.py
│   │   ├── compliance_service.py, compliance_impact_import.py
│   │   ├── urs_service.py
│   │   └── email_service.py
│   ├── integrations/                 # thin HTTP clients
│   │   ├── wazuh_client.py
│   │   ├── nessus_client.py
│   │   ├── ai_client.py, infomaniak_ai_client.py
│   ├── auth/                         # strategy-pattern auth
│   │   ├── orchestrator.py
│   │   ├── strategies/               # local, ldap, oidc, saml
│   │   ├── jit_provisioner.py, role_mapper.py
│   ├── models/                       # SQLAlchemy
│   │   └── vulnerability.py, asset.py, user.py, group.py, ...
│   ├── schemas/                      # Pydantic v2 request/response
│   ├── scheduler.py                  # APScheduler
│   ├── main.py                       # FastAPI app + middleware
│   └── deps.py                       # auth dependency, DB session
├── alembic/
│   └── versions/                     # 001 .. 022 migrations
├── alembic.ini
├── frontend/
│   ├── app/                          # Next.js 14 App Router
│   │   ├── page.tsx                  # Dashboard (2-widget Recent Critical + Newly Published)
│   │   ├── vulnerabilities/page.tsx  # main list
│   │   ├── vulnerabilities/[id]/     # detail
│   │   ├── assets/, compliance/, scans/, notifications/, settings/
│   ├── components/
│   ├── lib/api.ts                    # axios + auth header
│   ├── types/index.ts
│   └── public/logo.png
├── docs/
│   └── TROUBLESHOOTING.md
├── docker-compose.yml
├── ARCHITECTURE.md
├── DATABASE_SCHEMA.md
├── README.md                         # stable main feature set
└── README.DEV.md                     # dev-branch additions (this branch)

🚀 Quick Start

# 1. Clone
git clone <repo> && cd vulnerability-dashboard

# 2. Configure .env (see ARCHITECTURE.md §6 for full list)
cp .env.example .env
$EDITOR .env  # set DATABASE_URL, JWT_SECRET, AUTH_PROVIDER_CRYPTO_KEY,
              # WAZUH_API_URL/USER/PASS, WAZUH_INDEXER_URL

# 3. Start
docker compose up -d

# 4. First-start bootstrap creates the admin via /auth/setup-admin (run once)
curl -X POST http://localhost:8000/api/v1/auth/setup-admin \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"<strong-pass>","email":"you@example.com"}'

# 5. Open
#    UI:    http://localhost:3000
#    API:   http://localhost:8000/docs

docker compose up -d runs alembic upgrade head automatically on backend boot — no separate migration step needed for fresh deploys.


📊 Implemented Features

Threat-intel enrichment (5 sources)

  • EPSS — FIRST.org probability of exploitation, refreshed every 24 h
  • CISA KEV — known-exploited catalog, ~1500 CVEs, ransomware-use flag
  • ENISA EUVD — EU exploited + ENISA-flagged critical, ~1600 CVEs
  • CISA Vulnrichment — authoritative per-CVE CVSSv3.1 corrections + SSVC decision points (Exploitation / Technical Impact / Automatable). Parses CNA + ADP containers.
  • NVD REST API — 2nd-stage fallback for CVEs Vulnrichment hasn't analysed yet (rate-limit bounded ≤ 100 per run)
  • cvelistV5 — 3rd-stage backstop, exhaustive ~250 k CVEs, 12 h on-disk ZIP cache

All sources free, no API key required.

Scoring

  • Priority Score (0-100) — CVSS + exploit-bonus (KEV/EUVD/EPSS/SSVC/Wazuh/Nessus, capped via max) + SSVC technical-impact/automatable add-on + asset-criticality multiplier + age bonus
  • CPR Score (0-100) — JacquesKruger percentile-weighted blend: CVSS×10 × 0.6 + EPSS_percentile × 100 × 0.4
  • Tenable VPR (0-10) — surfaced as parallel reference, not folded into Priority/CPR
  • URS (0-100) — Unified Risk Score combining AVS (CPR-derived) + ASS (impact-weighted SCA) × criticality multiplier, daily snapshots feed trend arrow

Multi-scanner ingest

  • Wazuh — agent-based vulnerability detection + SCA compliance
  • Nessus — REST-API import alongside Wazuh on the same (cve_id, asset_id) row; pseudo-CVE pseudo-IDs for non-CVE plugins; per-host scan rows
  • Manual overrides — 3-stage CVSS/SSVC/fixed_version cascade triggered by "Correct CVSS" button or 03:00 UTC nightly job

Multi-provider authentication

  • Local — username + password (bcrypt cost-12) + optional TOTP MFA
  • LDAPS — search-then-bind, encrypted bind password
  • OIDC — PKCE + JWKS, Entra ID / Okta / Keycloak / Google
  • SAML 2.0 — python3-saml, strict signature + XSW protection
  • JIT provisioning + group-to-role mapping editable in UI

Compliance + URS

  • Wazuh SCA pulled per agent and stored as compliance_results + compliance_checks
  • CIS-Benchmark impact CSV upload weighted into per-policy weighted_score
  • Unified Risk Score per asset with daily snapshots and 7-day trend arrow

SLA tracking + notifications

  • Per-severity SLA days configurable globally + per policy
  • Hourly SLA breach checker → digest or single mode mails
  • Policy DISABLED status suppresses mails for that policy's assets
  • Master kill-switch via sla_breach_enabled setting
  • Per-vuln 24 h throttle prevents repeat-pinging
  • New-vuln digest after every Wazuh/Nessus sync

UI features

  • 2-widget dashboard ("Recent Critical" + "Newly Published")
  • Vulns list with VPR badge, EPSS / KEV / EUVD / SSVC pills, cross-scanner confirmation, badge legend popover
  • Per-vuln detail with threat-intel sections + Priority/CPR breakdown
  • Compliance page with per-asset modal and URS table
  • Settings UI for SMTP, Nessus, LDAP/OIDC/SAML, role mappings, mail templates

🔧 Configuration

.env keys at a glance:

# Database
DATABASE_URL=postgresql://vulnmanager:<pw>@postgres/vulnmanager

# JWT
JWT_SECRET=<random-256-bit>
JWT_ALGORITHM=HS256
JWT_EXPIRY_MINUTES=60

# Auth crypto (Fernet, encrypts TOTP + LDAP pw + SMTP pw at rest)
AUTH_PROVIDER_CRYPTO_KEY=<fernet-key>

# Wazuh
WAZUH_API_URL=https://wazuh-manager:55000
WAZUH_INDEXER_URL=https://wazuh-indexer:9200
WAZUH_API_USER=truevuln-readonly
WAZUH_API_PASS=<pw>

# Optional
DASHBOARD_URL=http://localhost:3000          # used in mail links
INFOMANIAK_API_KEY=<key>                      # AI analysis
LDAP_BIND_PASSWORD_BOOTSTRAP=<pw>             # one-shot for first LDAP setup
HTTPS_PROXY=http://proxy:8080                 # for outbound enrichment

All UI-relevant config (SMTP, Nessus, LDAP, OIDC, SAML, role mappings, mail templates) lives in the settings table — no env-var redeploy needed.


📡 API Overview

See ARCHITECTURE.md §5 for the endpoint reference and /docs (Swagger UI) on the running backend for the full schema. Curl-friendly examples in README.DEV.md.


🔒 RBAC Permissions

Role Capabilities
admin Everything — user management, provider config, settings, role mappings, audit log
editor Sync, override, enrich, assign, defer, mark FP, schedule scans, compliance refresh, impact import
viewer Read-only — list / search vulns, assets, scans, reports, exports

Enforced by require_role() dependency on every router. JWT carries the role claim; group→role mapping re-evaluates on each SSO/LDAP login.


🗄️ Database Schema (PostgreSQL)

See DATABASE_SCHEMA.md for column-level detail. 20+ tables, 22 alembic migrations. Key tables:

  • users, groups, user_groups
  • assets, asset_groups
  • vulnerabilities
  • scans, scan_schedules
  • policies
  • notification_logs, audit_logs
  • compliance_results, compliance_checks, compliance_impacts, asset_risk_snapshots
  • settings (KV store), ai_analyses, ai_reports

🎨 Workflow Examples

Daily admin morning routine

  1. Dashboard widget shows URS trend + Critical / Newly Published CVEs
  2. SLA-breach mail already arrived (00:00–08:00 stack)
  3. Click "Correct CVSS" once a week to refresh Vulnrichment-corrected scores
  4. Compliance widget shows worst 5 assets — drill in via per-asset modal
  5. Investigate "Recent Critical" rows — KEV / EUVD badges flag externally-confirmed exploit risk

Adding a Nessus scan

  1. Settings → Integrations → Tenable Nessus → Configure
  2. Paste Base URL + API access/secret keys → Test connection
  3. Pick default scan IDs → Save
  4. Sync now (or wait for next scheduled run)
  5. Vulns list now shows Wazuh + Nessus + cross-confirmed rows

Updating a Vulnrichment-corrected score for a single CVE

TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"…"}' | jq -r .access_token)

curl -X POST "http://localhost:8000/api/v1/vulnerabilities/override/vulnrichment?dry_run=false&cve_ids=CVE-2026-8390" \
  -H "Authorization: Bearer $TOKEN"

Response stats include not_found (CVEs CISA hasn't analysed yet — silently skipped).

Disabling SLA mails system-wide

docker compose exec postgres psql -U vulnmanager -d vulnmanager -c "
INSERT INTO settings (key, value) VALUES ('sla_breach_enabled','false')
ON CONFLICT (key) DO UPDATE SET value='false';"

Re-enable:

UPDATE settings SET value='true' WHERE key='sla_breach_enabled';

🚧 Known Limitations

  • sla_breach_enabled toggle has no UI yet — DB-only (Settings page improvement on backlog)
  • CIRCL aggregator not used — we hit CISA + ENISA directly
  • No real-time KEV push — we poll the CISA feed (24 h cache)
  • No two-way Nessus FP sync — marking false-positive in TrueVuln doesn't update Nessus
  • Wazuh-side fix-version field doesn't exist in the indexer schema — relying entirely on Vulnrichment/NVD/cvelistV5 cascade for PATCH AVAILABLE
  • Per-framework URS breakdown schema-ready but UI hidden
  • No WebAuthn / FIDO2 — TOTP is the only second factor

🛠️ Development

Run tests

docker compose exec backend pytest tests/

Smoke test covers auth, RBAC, vuln CRUD, sync mocking. Coverage is partial — integration paths (Wazuh, Nessus, enrichment HTTP) rely on manual verification against a live environment.

Add a new vuln column

  1. Edit app/models/vulnerability.py — add the Column(...)
  2. Edit app/schemas/vulnerability.py (or wherever the Pydantic schemas live)
  3. Generate migration:
    docker compose exec backend alembic revision --autogenerate -m "add foo column"
    
  4. Review the generated file (autogenerate misses index intent sometimes)
  5. alembic upgrade head
  6. Update _build_vuln_response() in app/routers/vulnerabilities.py if it should be in the API response

Add a new threat-intel source

  1. New service module in app/services/ (e.g. mysource_service.py)
  2. Cache feed JSON in settings table for 24 h
  3. Wire into enrichment_service.refresh_threat_intel_enrichment()
  4. Add columns to vulnerabilities table via alembic
  5. Surface in _build_vuln_response() + frontend list/detail

📈 Performance Optimisations

  • Wazuh indexer pagination beyond OpenSearch 10 000-hit cap (search-after)
  • Vulnrichment cascade auto-routes to ZIP when > 25 CVEs requested
  • cvelistV5 ZIP cached on disk 12 h
  • NVD stage capped at 100 CVEs per run (rate-limit safe)
  • Async "Correct CVSS" — long-running cascade returns a job_id and a progress card
  • Indexed columns on every filter / sort path
  • sources / enrichment_sources JSON columns avoid join-heavy queries

📚 Further Documentation

  • ARCHITECTURE.md — system topology, security model, scheduler jobs
  • DATABASE_SCHEMA.md — every column, every enum, every migration
  • CODEBASE_KNOWLEDGE_BASE.md — module-by-module walk-through for new contributors
  • README.DEV.md — dev-branch feature deep-dives (auth, Nessus, compliance, URS)
  • docs/TROUBLESHOOTING.md — common production issues and fixes

🐛 Debugging

# Backend logs (tail and follow)
docker compose logs -f backend

# All services
docker compose logs -f

# Postgres logs
docker compose logs -f postgres

# Inside backend container
docker compose exec backend bash
docker compose exec backend python3 -c "from app.services.enrichment_service import refresh_threat_intel_enrichment; refresh_threat_intel_enrichment()"

# DB shell
docker compose exec postgres psql -U vulnmanager -d vulnmanager

docs/TROUBLESHOOTING.md lists symptom → cause → fix patterns for the recurring production issues (alembic head conflicts, MFA setup 500s, LDAP bind decryption failures, missing SLA mails, etc.).


📧 Support

Open an issue on GitHub. For security vulnerabilities in TrueVuln itself, see SECURITY.md.