Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 4,458 Bytes
d543fc1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | """
core/confidence.py — Confidence Tier Tracker
=============================================
Defines three evidence tiers for injection/exploit findings and enforces
automatic severity/CVSS capping so that weak-signal signals never appear as
Critical or High.
Tiers
-----
CONFIRMED Direct proof: reflected unique token, OOB callback received,
timing delta reproduced ≥3×, or actual data exfiltrated.
LIKELY Two or more independent weak signals agree (e.g. error pattern
PLUS response-time anomaly), but no direct proof.
UNCONFIRMED Single weak signal only (e.g. one error substring, one generic
500 response). Auto-capped to severity=Low, CVSS≤3.9.
PENDING OOB probe sent; awaiting external callback. Resolved to CONFIRMED
or EXPIRED at end-of-scan.
Usage
-----
from scanners.core.confidence import ConfidenceTracker as CT
sev = CT.cap_severity(severity, confidence)
cvss = CT.cap_cvss(cvss_score, confidence)
self.add_vuln(..., severity=sev, cvss_score=cvss, confidence=confidence)
"""
from __future__ import annotations
class ConfidenceTracker:
# Canonical tier strings (use these constants everywhere)
CONFIRMED = "Confirmed"
LIKELY = "Likely"
UNCONFIRMED = "Unconfirmed"
PENDING = "Pending"
VALID_TIERS = {CONFIRMED, LIKELY, UNCONFIRMED, PENDING}
# Severity order (ascending)
_SEV_ORDER = ["Info", "Low", "Medium", "High", "Critical"]
# Maximum allowed severity per tier
_MAX_SEV: dict[str, str] = {
CONFIRMED: "Critical", # no cap
LIKELY: "High", # confirmed-tier cap not needed; High is reasonable
UNCONFIRMED: "Low", # single weak signal — never escalate
PENDING: "Medium", # OOB probe sent but no callback yet
}
# Maximum allowed CVSS per tier
_MAX_CVSS: dict[str, float] = {
CONFIRMED: 10.0,
LIKELY: 6.9,
UNCONFIRMED: 3.9,
PENDING: 5.9,
}
# ------------------------------------------------------------------
@classmethod
def cap_severity(cls, severity: str, confidence: str) -> str:
"""
Return severity capped to the tier maximum.
Example:
cap_severity("Critical", "Unconfirmed") → "Low"
cap_severity("Critical", "Confirmed") → "Critical"
"""
confidence = cls.normalize(confidence)
max_sev = cls._MAX_SEV.get(confidence, "Low")
try:
sev_idx = cls._SEV_ORDER.index(severity)
except ValueError:
sev_idx = 2 # default to Medium index
try:
max_idx = cls._SEV_ORDER.index(max_sev)
except ValueError:
max_idx = 2
return cls._SEV_ORDER[min(sev_idx, max_idx)]
# ------------------------------------------------------------------
@classmethod
def cap_cvss(cls, cvss: float, confidence: str) -> float:
"""
Return CVSS score capped to the tier maximum.
Example:
cap_cvss(9.8, "Unconfirmed") → 3.9
cap_cvss(9.8, "Likely") → 6.9
cap_cvss(9.8, "Confirmed") → 9.8
"""
confidence = cls.normalize(confidence)
max_cvss = cls._MAX_CVSS.get(confidence, 3.9)
return min(float(cvss), max_cvss)
# ------------------------------------------------------------------
@classmethod
def normalize(cls, confidence: str) -> str:
"""Return a valid tier string, defaulting to UNCONFIRMED for unknown values."""
if confidence in cls.VALID_TIERS:
return confidence
# Case-insensitive lookup
for tier in cls.VALID_TIERS:
if confidence.lower() == tier.lower():
return tier
return cls.UNCONFIRMED
# ------------------------------------------------------------------
@classmethod
def apply(
cls,
severity: str,
cvss: float,
confidence: str,
) -> tuple[str, float, str]:
"""
Convenience: return (capped_severity, capped_cvss, normalized_confidence).
Usage:
sev, cvss, conf = ConfidenceTracker.apply(sev, cvss, confidence)
self.add_vuln(..., severity=sev, cvss_score=cvss, confidence=conf)
"""
conf = cls.normalize(confidence)
return cls.cap_severity(severity, conf), cls.cap_cvss(cvss, conf), conf
|