docs(README.DEV): document Nessus override + SSVC + migrations 011/012

- Merge logic block reflects new Nessus-wins behaviour (cvss/severity
  override during sync, not max-merge)
- Adds Manual Overrides section covering vuln_override_service.py +
  /override/check, /override/nessus, /override/vulnrichment endpoints
- Schema table grows nessus_vpr_score (011) and exploitation_status (012)
- Verification block updated to alembic head 012 and the new
  scores_overridden stat in sync response

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-15 08:04:27 +02:00
parent 97a951d42c
commit 68ed824d5f
+39 -6
View File
@@ -683,12 +683,15 @@ reports.
| `vulnerabilities.nessus_finding_uuid` | string | per-host-per-plugin stable id |
| `vulnerabilities.first_detected_by` | string | which scanner first reported (wazuh/nessus/manual) |
| `vulnerabilities.cve_id` | widened 20 → 50 | room for NESSUS-PLUGIN-* pseudo-IDs |
| `vulnerabilities.nessus_vpr_score` | float indexed (mig. 011) | Tenable VPR 010 alongside our own priority |
| `vulnerabilities.exploitation_status` | string indexed (mig. 012) | SSVC: `none|poc|active|widespread` from Vulnrichment |
| `assets.nessus_host_uuid` | string indexed | pin Nessus host after first match |
| `scan_schedules.scanner_type` | string default 'wazuh' | route scheduled syncs to wazuh or nessus |
Migration 010 backfills `sources='["wazuh"]'` and
`first_detected_by='wazuh'` on every existing vulnerability — no data
loss, zero behaviour change until Nessus is configured.
loss, zero behaviour change until Nessus is configured. Migrations 011
+ 012 are idempotent (`ADD COLUMN IF NOT EXISTS`).
## Asset matching
@@ -710,20 +713,49 @@ the VulnCheck inventory.
existing = find(cve, asset)
if existing:
existing.add_source("nessus")
existing.severity = max(existing.severity, nessus_severity)
existing.cvss_score = max(existing.cvss_score, nessus_cvss)
# Nessus wins when it provides a value (typical case: Wazuh dropped
# a placeholder 10.0 on the row, Nessus has the real per-plugin score).
if nessus_cvss is not None:
existing.cvss_score = nessus_cvss
if nessus_severity and nessus_severity != "none":
existing.severity = nessus_severity
else:
existing.severity = max(existing.severity, nessus_severity)
existing.nessus_plugin_id = plugin_id
existing.nessus_vpr_score = vpr_score # always latest
if existing.status == patched:
existing.status = open # Nessus sees it again → reopen
else:
create new with sources=["nessus"], first_detected_by="nessus"
```
Override safety: if Nessus has no CVSS for a CVE (`None`), the existing
Wazuh value is preserved — no data wipe. Same for severity = `none`.
When a previously-Nessus-flagged CVE is missing from this scan run, we
**only drop** `"nessus"` from the sources list. If the list empties
(no scanner sees it anymore), status flips to patched. Wazuh findings
are never removed by a Nessus sync.
## Manual overrides (CISA Vulnrichment + Nessus)
`app/services/vuln_override_service.py` provides on-demand correction of
CVSS/severity/exploitation data from authoritative feeds. Used when
Wazuh-only findings need their placeholder 10.0 scores fixed without
waiting for a Nessus sync.
- `POST /api/v1/vulnerabilities/override/check` — dry-run, lists rows
that would change
- `POST /api/v1/vulnerabilities/override/nessus/{asset_id}` — pull from
Nessus plugin output for one asset
- `POST /api/v1/vulnerabilities/override/vulnrichment?dry_run=…` — pull
CISA Vulnrichment JSON feed (all CVEs)
Detects "Wazuh placeholder 10.0" + score diffs ≥ 1.0 between current
and verified value. Writes new `vulnerabilities.exploitation_status`
(SSVC: `none|poc|active|widespread`) — rendered as colored badge in
the Vulns list when value ≠ `none`.
## Endpoints
| Method | Path | Role | Purpose |
@@ -795,8 +827,8 @@ Settings → Integrations gains a **Tenable Nessus** row with:
# 1. Migrate
git pull origin dev
docker compose build backend frontend && docker compose up -d backend frontend
docker compose exec backend alembic upgrade head # 009 → 010
docker compose exec backend alembic current # 010 (head)
docker compose exec backend alembic upgrade head # 009 → 012
docker compose exec backend alembic current # 012 (head)
# 2. Backfill check
docker compose exec postgres psql -U vulnmanager -d vulnmanager -c "
@@ -815,7 +847,8 @@ curl -X POST http://<host>/api/v1/vulnerabilities/nessus/sync \
-H "Content-Type: application/json" \
-d '{}'
# returns {scans_processed, hosts_synced, vulns_created, vulns_merged,
# vulns_marked_patched, unmatched_hosts[], notifications:{…}}
# scores_overridden, vulns_marked_patched, unmatched_hosts[],
# notifications:{…}}
# 5. Cross-confirmation listing (CVEs in both scanners)
curl -s "http://<host>/api/v1/vulnerabilities?cross_confirmed=true&limit=5" \