fix(cvss): clamp out-of-range scanner values to None at extraction

Tester saw cvss_score=-1 in the DB plus cpr_score=-9.3 in the UI for
some CVEs. CPR math is purely multiplicative, so a negative CPR can
only come from a negative CVSS. Source confirmed: Wazuh-Indexer emits
-1 as a placeholder when it could not score a package, and we passed
it through to the DB unchanged. The Nessus plugin extractor had the
same gap.

Both clients now validate the extracted base_score with a
'0.0 <= f <= 10.0' guard and return None on anything outside the
CVSSv3 spec range. Downstream CPR + priority calculations already
handle None correctly (calculate_cpr_score returns None when either
cvss_score or epss_score is missing). No DB clean-up required —
new syncs overwrite the bad values.

For existing -1 rows, ops can wipe them once:
    UPDATE vulnerabilities SET cvss_score = NULL
    WHERE cvss_score < 0 OR cvss_score > 10;
This commit is contained in:
2026-05-18 11:29:48 +02:00
parent de896f7e28
commit 9cb9051854
2 changed files with 21 additions and 2 deletions
+7 -1
View File
@@ -516,7 +516,13 @@ class NessusClient:
if v is None:
continue
try:
return float(v)
f = float(v)
except (TypeError, ValueError):
continue
# Clamp to the CVSS spec range. Some plugins emit junk
# like -1 or 99 for un-scored vulns; treat those as
# "no score" so the downstream CPR math stays non-
# negative and within [0, 100].
if 0.0 <= f <= 10.0:
return f
return None
+14 -1
View File
@@ -440,7 +440,20 @@ class WazuhClient:
continue
# Try multiple score field paths for compatibility
base_score = score.get("base") or score.get("base_score")
raw_score = score.get("base") or score.get("base_score")
# Wazuh-Indexer emits -1 / out-of-range placeholders for
# packages it could not score. Clamp anything outside the
# CVSSv3 spec range [0.0, 10.0] back to None so downstream
# CPR maths cannot produce negative results (tester saw
# CPR=-9.3 driven by cvss_score=-1).
base_score = None
try:
if raw_score is not None:
f = float(raw_score)
if 0.0 <= f <= 10.0:
base_score = f
except (TypeError, ValueError):
base_score = None
# Mapping auf das interne Format
results.append({