Spaces:
Running
Running
deploy(hf): sync szl-holdings/a11oy@bec855ed0ff1e975571c7d42357e019f21251999 derived COPY set
Browse filesReusable Dockerfile-COPY-derived deploy from szl-holdings/a11oy bec855ed0ff1e975571c7d42357e019f21251999.
Files: 1346 Pruned: 0
Derived from Dockerfile COPY sources (NO hand-maintained allowlist).
Signed-off-by: SZL Holdings <noreply@szlholdings.ai>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
szl_connectors/bindings.py
CHANGED
|
@@ -12,7 +12,7 @@ from __future__ import annotations
|
|
| 12 |
|
| 13 |
TAB_BINDINGS: dict[str, list[str]] = {
|
| 14 |
# a11oy governed-AI / security verticals (keyless → CONNECTED now)
|
| 15 |
-
"vuln": ["nvd_cve", "cisa_kev", "epss"],
|
| 16 |
"attack": ["mitre_attack"],
|
| 17 |
"macro": ["fred", "sec_edgar"],
|
| 18 |
"research": ["arxiv", "hf_hub", "github"],
|
|
|
|
| 12 |
|
| 13 |
TAB_BINDINGS: dict[str, list[str]] = {
|
| 14 |
# a11oy governed-AI / security verticals (keyless → CONNECTED now)
|
| 15 |
+
"vuln": ["nvd_cve", "cisa_kev", "epss", "defensive_fusion"],
|
| 16 |
"attack": ["mitre_attack"],
|
| 17 |
"macro": ["fred", "sec_edgar"],
|
| 18 |
"research": ["arxiv", "hf_hub", "github"],
|
szl_connectors/data_sources/security.py
CHANGED
|
@@ -43,7 +43,7 @@ class CisaKevConnector(Connector):
|
|
| 43 |
free_tier = True
|
| 44 |
provider_base = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
| 45 |
docs_url = "https://www.cisa.gov/known-exploited-vulnerabilities-catalog"
|
| 46 |
-
schema_preview = ["cveID", "vendorProject", "product", "vulnerabilityName", "dateAdded", "knownRansomwareCampaignUse"]
|
| 47 |
# raw.githubusercontent mirror (not rate-limited) as fallback source
|
| 48 |
_mirror = "https://raw.githubusercontent.com/cisagov/kev-data/develop/known_exploited_vulnerabilities.json"
|
| 49 |
|
|
@@ -263,5 +263,393 @@ class GithubConnector(Connector):
|
|
| 263 |
return self._ready_records(f"GitHub API HTTP {st}")
|
| 264 |
|
| 265 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
__all__ = ["CisaKevConnector", "NvdCveConnector", "EpssConnector",
|
| 267 |
-
"MitreAttackConnector", "GithubConnector"
|
|
|
|
|
|
| 43 |
free_tier = True
|
| 44 |
provider_base = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
| 45 |
docs_url = "https://www.cisa.gov/known-exploited-vulnerabilities-catalog"
|
| 46 |
+
schema_preview = ["cveID", "vendorProject", "product", "vulnerabilityName", "dateAdded", "knownRansomwareCampaignUse", "requiredAction"]
|
| 47 |
# raw.githubusercontent mirror (not rate-limited) as fallback source
|
| 48 |
_mirror = "https://raw.githubusercontent.com/cisagov/kev-data/develop/known_exploited_vulnerabilities.json"
|
| 49 |
|
|
|
|
| 263 |
return self._ready_records(f"GitHub API HTTP {st}")
|
| 264 |
|
| 265 |
|
| 266 |
+
# ── Killinchu Defensive CVE Fusion ──────────────────────────────────────────
|
| 267 |
+
# Correlates three official defensive sources for one exact CVE. This is a
|
| 268 |
+
# prioritization instrument, not exploit guidance, asset scanning, or action
|
| 269 |
+
# authority. Missing source evidence is omitted from the weighted denominator
|
| 270 |
+
# rather than silently treated as a zero-risk observation.
|
| 271 |
+
@register
|
| 272 |
+
class DefensiveFusionConnector(Connector):
|
| 273 |
+
id = "defensive_fusion"
|
| 274 |
+
label = "Killinchu Defensive CVE Fusion"
|
| 275 |
+
category = "vuln"
|
| 276 |
+
auth_kind = "none"
|
| 277 |
+
free_tier = True
|
| 278 |
+
provider_base = "source-bound:CISA-KEV+NIST-NVD-2.0+FIRST-EPSS"
|
| 279 |
+
docs_url = "https://github.com/szl-holdings/killinchu/blob/main/docs/DEFENSIVE_FUSION_WAVE4.md"
|
| 280 |
+
schema_preview = [
|
| 281 |
+
"cve",
|
| 282 |
+
"priority",
|
| 283 |
+
"priority_score",
|
| 284 |
+
"coverage",
|
| 285 |
+
"known_exploited",
|
| 286 |
+
"known_ransomware_use",
|
| 287 |
+
"cvss",
|
| 288 |
+
"epss",
|
| 289 |
+
"epss_percentile",
|
| 290 |
+
"recommended_action",
|
| 291 |
+
"normalized_evidence_sha256",
|
| 292 |
+
]
|
| 293 |
+
|
| 294 |
+
_cve_pattern = r"^CVE-\d{4}-\d{4,}$"
|
| 295 |
+
_weights = {
|
| 296 |
+
"cvss": 0.35,
|
| 297 |
+
"epss": 0.30,
|
| 298 |
+
"known_exploited": 0.30,
|
| 299 |
+
"known_ransomware_use": 0.05,
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
@classmethod
|
| 303 |
+
def _normalize_cve(cls, value: Any) -> str | None:
|
| 304 |
+
import re
|
| 305 |
+
|
| 306 |
+
candidate = str(value or "").strip().upper()
|
| 307 |
+
return candidate if re.fullmatch(cls._cve_pattern, candidate) else None
|
| 308 |
+
|
| 309 |
+
@staticmethod
|
| 310 |
+
def _as_probability(value: Any) -> float | None:
|
| 311 |
+
try:
|
| 312 |
+
number = float(value)
|
| 313 |
+
except (TypeError, ValueError):
|
| 314 |
+
return None
|
| 315 |
+
if number < 0.0 or number > 1.0:
|
| 316 |
+
return None
|
| 317 |
+
return number
|
| 318 |
+
|
| 319 |
+
@staticmethod
|
| 320 |
+
def _as_cvss(value: Any) -> float | None:
|
| 321 |
+
try:
|
| 322 |
+
number = float(value)
|
| 323 |
+
except (TypeError, ValueError):
|
| 324 |
+
return None
|
| 325 |
+
if number < 0.0 or number > 10.0:
|
| 326 |
+
return None
|
| 327 |
+
return number
|
| 328 |
+
|
| 329 |
+
@staticmethod
|
| 330 |
+
def _nvd_record(raw: Any, cve_id: str) -> dict[str, Any] | None:
|
| 331 |
+
if not isinstance(raw, dict):
|
| 332 |
+
return None
|
| 333 |
+
for wrapper in raw.get("vulnerabilities", []) or []:
|
| 334 |
+
if not isinstance(wrapper, dict):
|
| 335 |
+
continue
|
| 336 |
+
cve = wrapper.get("cve")
|
| 337 |
+
if not isinstance(cve, dict) or str(cve.get("id") or "").upper() != cve_id:
|
| 338 |
+
continue
|
| 339 |
+
metrics = cve.get("metrics") if isinstance(cve.get("metrics"), dict) else {}
|
| 340 |
+
score = severity = vector = version = None
|
| 341 |
+
for metric_name, metric_version in (
|
| 342 |
+
("cvssMetricV40", "4.0"),
|
| 343 |
+
("cvssMetricV31", "3.1"),
|
| 344 |
+
("cvssMetricV30", "3.0"),
|
| 345 |
+
("cvssMetricV2", "2.0"),
|
| 346 |
+
):
|
| 347 |
+
rows = metrics.get(metric_name) or []
|
| 348 |
+
if not rows or not isinstance(rows[0], dict):
|
| 349 |
+
continue
|
| 350 |
+
data = rows[0].get("cvssData") or {}
|
| 351 |
+
if not isinstance(data, dict):
|
| 352 |
+
continue
|
| 353 |
+
score = DefensiveFusionConnector._as_cvss(data.get("baseScore"))
|
| 354 |
+
severity = data.get("baseSeverity") or rows[0].get("baseSeverity")
|
| 355 |
+
vector = data.get("vectorString")
|
| 356 |
+
version = metric_version
|
| 357 |
+
if score is not None:
|
| 358 |
+
break
|
| 359 |
+
weaknesses: list[str] = []
|
| 360 |
+
for weakness in cve.get("weaknesses", []) or []:
|
| 361 |
+
if not isinstance(weakness, dict):
|
| 362 |
+
continue
|
| 363 |
+
for description in weakness.get("description", []) or []:
|
| 364 |
+
if not isinstance(description, dict):
|
| 365 |
+
continue
|
| 366 |
+
value = str(description.get("value") or "").strip().upper()
|
| 367 |
+
if value.startswith("CWE-") and value not in weaknesses:
|
| 368 |
+
weaknesses.append(value[:40])
|
| 369 |
+
return {
|
| 370 |
+
"id": cve_id,
|
| 371 |
+
"cvss": score,
|
| 372 |
+
"severity": str(severity or "UNAVAILABLE").upper(),
|
| 373 |
+
"vector": str(vector or "")[:160] or None,
|
| 374 |
+
"cvss_version": version,
|
| 375 |
+
"weaknesses": weaknesses[:20],
|
| 376 |
+
"published": str(cve.get("published") or "")[:32] or None,
|
| 377 |
+
"last_modified": str(cve.get("lastModified") or "")[:32] or None,
|
| 378 |
+
"vuln_status": str(cve.get("vulnStatus") or "UNAVAILABLE")[:80],
|
| 379 |
+
}
|
| 380 |
+
return None
|
| 381 |
+
|
| 382 |
+
@staticmethod
|
| 383 |
+
def _epss_record(raw: Any, cve_id: str) -> dict[str, Any] | None:
|
| 384 |
+
if not isinstance(raw, dict):
|
| 385 |
+
return None
|
| 386 |
+
for row in raw.get("data", []) or []:
|
| 387 |
+
if not isinstance(row, dict) or str(row.get("cve") or "").upper() != cve_id:
|
| 388 |
+
continue
|
| 389 |
+
score = DefensiveFusionConnector._as_probability(row.get("epss"))
|
| 390 |
+
percentile = DefensiveFusionConnector._as_probability(row.get("percentile"))
|
| 391 |
+
return {
|
| 392 |
+
"cve": cve_id,
|
| 393 |
+
"epss": score,
|
| 394 |
+
"percentile": percentile,
|
| 395 |
+
"date": str(row.get("date") or "")[:32] or None,
|
| 396 |
+
}
|
| 397 |
+
return None
|
| 398 |
+
|
| 399 |
+
@classmethod
|
| 400 |
+
def _priority(
|
| 401 |
+
cls,
|
| 402 |
+
*,
|
| 403 |
+
cvss: float | None,
|
| 404 |
+
epss: float | None,
|
| 405 |
+
kev_observed: bool,
|
| 406 |
+
known_exploited: bool,
|
| 407 |
+
ransomware_observed: bool,
|
| 408 |
+
ransomware_known: bool,
|
| 409 |
+
) -> tuple[float | None, str, dict[str, float]]:
|
| 410 |
+
observed: dict[str, float] = {}
|
| 411 |
+
if cvss is not None:
|
| 412 |
+
observed["cvss"] = cvss / 10.0
|
| 413 |
+
if epss is not None:
|
| 414 |
+
observed["epss"] = epss
|
| 415 |
+
if kev_observed:
|
| 416 |
+
observed["known_exploited"] = 1.0 if known_exploited else 0.0
|
| 417 |
+
if ransomware_observed:
|
| 418 |
+
observed["known_ransomware_use"] = 1.0 if ransomware_known else 0.0
|
| 419 |
+
denominator = sum(cls._weights[key] for key in observed)
|
| 420 |
+
if denominator <= 0.0:
|
| 421 |
+
return None, "UNAVAILABLE", observed
|
| 422 |
+
score = sum(cls._weights[key] * value for key, value in observed.items()) / denominator
|
| 423 |
+
score = min(0.99, max(0.0, score))
|
| 424 |
+
if known_exploited or ransomware_known or score >= 0.85:
|
| 425 |
+
priority = "IMMEDIATE"
|
| 426 |
+
elif score >= 0.65:
|
| 427 |
+
priority = "HIGH"
|
| 428 |
+
elif score >= 0.40:
|
| 429 |
+
priority = "ELEVATED"
|
| 430 |
+
else:
|
| 431 |
+
priority = "ROUTINE"
|
| 432 |
+
return round(score, 4), priority, observed
|
| 433 |
+
|
| 434 |
+
@staticmethod
|
| 435 |
+
def _recommendation(priority: str) -> str:
|
| 436 |
+
return {
|
| 437 |
+
"IMMEDIATE": (
|
| 438 |
+
"Confirm affected assets, apply the vendor or CISA mitigation, reduce exposure, "
|
| 439 |
+
"and verify remediation under an approved defensive change process."
|
| 440 |
+
),
|
| 441 |
+
"HIGH": (
|
| 442 |
+
"Schedule accelerated remediation, validate compensating controls, and verify "
|
| 443 |
+
"the affected inventory against the vendor advisory."
|
| 444 |
+
),
|
| 445 |
+
"ELEVATED": (
|
| 446 |
+
"Prioritize owner review, patch planning, and exposure validation in the next "
|
| 447 |
+
"defensive maintenance window."
|
| 448 |
+
),
|
| 449 |
+
"ROUTINE": (
|
| 450 |
+
"Track the CVE through normal vulnerability management and re-evaluate when "
|
| 451 |
+
"official KEV, CVSS, or EPSS evidence changes."
|
| 452 |
+
),
|
| 453 |
+
}.get(priority, "No defensive priority can be computed until official evidence is available.")
|
| 454 |
+
|
| 455 |
+
def _probe(self):
|
| 456 |
+
# A cheap exact-CVE EPSS lookup proves the composite transport without
|
| 457 |
+
# downloading the full KEV catalogue or ATT&CK bundle.
|
| 458 |
+
st, _ = http_json(EpssConnector.provider_base + "?cve=CVE-2021-44228")
|
| 459 |
+
return (st == 200), f"Defensive fusion EPSS dependency HTTP {st}"
|
| 460 |
+
|
| 461 |
+
def read(self, query: dict | None = None) -> Records:
|
| 462 |
+
import hashlib
|
| 463 |
+
import json
|
| 464 |
+
import urllib.parse as up
|
| 465 |
+
|
| 466 |
+
requested = (query or {}).get("cve") or (query or {}).get("q") or ""
|
| 467 |
+
cve_id = self._normalize_cve(requested)
|
| 468 |
+
if cve_id is None:
|
| 469 |
+
return Records(
|
| 470 |
+
connector_id=self.id,
|
| 471 |
+
category=self.category,
|
| 472 |
+
state=State.READY,
|
| 473 |
+
records=[],
|
| 474 |
+
source=self.provider_base,
|
| 475 |
+
live=False,
|
| 476 |
+
note="provide one exact CVE identifier, for example q=CVE-2021-44228",
|
| 477 |
+
schema_preview=list(self.schema_preview),
|
| 478 |
+
)
|
| 479 |
+
|
| 480 |
+
cache_key = f"defensive-fusion:{cve_id}"
|
| 481 |
+
cached = _cached(cache_key, 300)
|
| 482 |
+
if cached:
|
| 483 |
+
return cached
|
| 484 |
+
|
| 485 |
+
source_states = {
|
| 486 |
+
"cisa_kev": "UNAVAILABLE",
|
| 487 |
+
"nvd_cve": "UNAVAILABLE",
|
| 488 |
+
"epss": "UNAVAILABLE",
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
kev_entry: dict[str, Any] | None = None
|
| 492 |
+
kev_records = CisaKevConnector().read({"limit": 10000})
|
| 493 |
+
if kev_records.state == State.CONNECTED:
|
| 494 |
+
source_states["cisa_kev"] = "MEASURED"
|
| 495 |
+
kev_entry = next(
|
| 496 |
+
(
|
| 497 |
+
row
|
| 498 |
+
for row in kev_records.records
|
| 499 |
+
if str(row.get("cveID") or "").upper() == cve_id
|
| 500 |
+
),
|
| 501 |
+
None,
|
| 502 |
+
)
|
| 503 |
+
|
| 504 |
+
nvd_status, nvd_raw = http_json(
|
| 505 |
+
NvdCveConnector.provider_base
|
| 506 |
+
+ "?"
|
| 507 |
+
+ up.urlencode({"cveId": cve_id, "resultsPerPage": 1})
|
| 508 |
+
)
|
| 509 |
+
nvd = self._nvd_record(nvd_raw, cve_id) if nvd_status == 200 else None
|
| 510 |
+
if nvd_status == 200 and isinstance(nvd_raw, dict):
|
| 511 |
+
source_states["nvd_cve"] = "MEASURED"
|
| 512 |
+
|
| 513 |
+
epss_status, epss_raw = http_json(
|
| 514 |
+
EpssConnector.provider_base + "?" + up.urlencode({"cve": cve_id, "limit": 1})
|
| 515 |
+
)
|
| 516 |
+
epss = self._epss_record(epss_raw, cve_id) if epss_status == 200 else None
|
| 517 |
+
if epss_status == 200 and isinstance(epss_raw, dict):
|
| 518 |
+
source_states["epss"] = "MEASURED"
|
| 519 |
+
|
| 520 |
+
measured = sum(value == "MEASURED" for value in source_states.values())
|
| 521 |
+
coverage = "FULL" if measured == 3 else "PARTIAL" if measured else "NONE"
|
| 522 |
+
known_exploited = kev_entry is not None
|
| 523 |
+
ransomware_value = str(
|
| 524 |
+
(kev_entry or {}).get("knownRansomwareCampaignUse") or ""
|
| 525 |
+
).strip()
|
| 526 |
+
ransomware_observed = kev_entry is not None and bool(ransomware_value)
|
| 527 |
+
ransomware_known = ransomware_value.casefold() in {
|
| 528 |
+
"known",
|
| 529 |
+
"yes",
|
| 530 |
+
"true",
|
| 531 |
+
"known ransomware campaign use",
|
| 532 |
+
}
|
| 533 |
+
cvss = nvd.get("cvss") if nvd else None
|
| 534 |
+
epss_score = epss.get("epss") if epss else None
|
| 535 |
+
exact_evidence_observed = any(
|
| 536 |
+
value is not None for value in (kev_entry, nvd, epss)
|
| 537 |
+
)
|
| 538 |
+
if measured > 0 and not exact_evidence_observed:
|
| 539 |
+
result = Records(
|
| 540 |
+
connector_id=self.id,
|
| 541 |
+
category=self.category,
|
| 542 |
+
state=State.READY,
|
| 543 |
+
records=[],
|
| 544 |
+
source=self.provider_base,
|
| 545 |
+
live=False,
|
| 546 |
+
note=(
|
| 547 |
+
f"{coverage.lower()} transport coverage, but the exact CVE was not "
|
| 548 |
+
"present in returned official records; no priority fabricated"
|
| 549 |
+
),
|
| 550 |
+
schema_preview=list(self.schema_preview),
|
| 551 |
+
)
|
| 552 |
+
_put(cache_key, result)
|
| 553 |
+
return result
|
| 554 |
+
priority_score, priority, components = self._priority(
|
| 555 |
+
cvss=cvss,
|
| 556 |
+
epss=epss_score,
|
| 557 |
+
kev_observed=source_states["cisa_kev"] == "MEASURED",
|
| 558 |
+
known_exploited=known_exploited,
|
| 559 |
+
ransomware_observed=ransomware_observed,
|
| 560 |
+
ransomware_known=ransomware_known,
|
| 561 |
+
)
|
| 562 |
+
|
| 563 |
+
evidence_core = {
|
| 564 |
+
"cve": cve_id,
|
| 565 |
+
"source_states": source_states,
|
| 566 |
+
"kev": {
|
| 567 |
+
"known_exploited": known_exploited,
|
| 568 |
+
"date_added": (kev_entry or {}).get("dateAdded"),
|
| 569 |
+
"ransomware_use": ransomware_value or None,
|
| 570 |
+
},
|
| 571 |
+
"nvd": nvd,
|
| 572 |
+
"epss": epss,
|
| 573 |
+
"formula": {
|
| 574 |
+
"id": "killinchu.defensive-priority/v1",
|
| 575 |
+
"weights": self._weights,
|
| 576 |
+
"observed_components": components,
|
| 577 |
+
"missing_evidence_is_zero": False,
|
| 578 |
+
"maximum_score": 0.99,
|
| 579 |
+
},
|
| 580 |
+
}
|
| 581 |
+
digest = hashlib.sha256(
|
| 582 |
+
json.dumps(
|
| 583 |
+
evidence_core,
|
| 584 |
+
sort_keys=True,
|
| 585 |
+
separators=(",", ":"),
|
| 586 |
+
ensure_ascii=False,
|
| 587 |
+
).encode("utf-8")
|
| 588 |
+
).hexdigest()
|
| 589 |
+
|
| 590 |
+
if measured == 0:
|
| 591 |
+
result = Records(
|
| 592 |
+
connector_id=self.id,
|
| 593 |
+
category=self.category,
|
| 594 |
+
state=State.ERROR,
|
| 595 |
+
records=[],
|
| 596 |
+
source=self.provider_base,
|
| 597 |
+
live=False,
|
| 598 |
+
note="all three official defensive sources are unavailable; no priority fabricated",
|
| 599 |
+
schema_preview=list(self.schema_preview),
|
| 600 |
+
)
|
| 601 |
+
_put(cache_key, result)
|
| 602 |
+
return result
|
| 603 |
+
|
| 604 |
+
record = {
|
| 605 |
+
"cve": cve_id,
|
| 606 |
+
"priority": priority,
|
| 607 |
+
"priority_score": priority_score,
|
| 608 |
+
"coverage": coverage,
|
| 609 |
+
"sources_measured": measured,
|
| 610 |
+
"sources_expected": 3,
|
| 611 |
+
"source_states": source_states,
|
| 612 |
+
"known_exploited": known_exploited,
|
| 613 |
+
"known_ransomware_use": ransomware_known,
|
| 614 |
+
"ransomware_source_value": ransomware_value or None,
|
| 615 |
+
"cisa_date_added": (kev_entry or {}).get("dateAdded"),
|
| 616 |
+
"cisa_required_action": (kev_entry or {}).get("requiredAction"),
|
| 617 |
+
"cvss": cvss,
|
| 618 |
+
"cvss_severity": nvd.get("severity") if nvd else None,
|
| 619 |
+
"cvss_version": nvd.get("cvss_version") if nvd else None,
|
| 620 |
+
"cvss_vector": nvd.get("vector") if nvd else None,
|
| 621 |
+
"weaknesses": nvd.get("weaknesses", []) if nvd else [],
|
| 622 |
+
"nvd_published": nvd.get("published") if nvd else None,
|
| 623 |
+
"nvd_last_modified": nvd.get("last_modified") if nvd else None,
|
| 624 |
+
"epss": epss_score,
|
| 625 |
+
"epss_percentile": epss.get("percentile") if epss else None,
|
| 626 |
+
"epss_date": epss.get("date") if epss else None,
|
| 627 |
+
"recommended_action": self._recommendation(priority),
|
| 628 |
+
"formula": evidence_core["formula"],
|
| 629 |
+
"normalized_evidence_sha256": digest,
|
| 630 |
+
"truth_label": "MEASURED_DEFENSIVE_CORRELATION",
|
| 631 |
+
"action_authority": "DEFENSIVE_PRIORITIZATION_ONLY",
|
| 632 |
+
"human_approval_required": True,
|
| 633 |
+
"exploit_content_included": False,
|
| 634 |
+
"asset_scanning_performed": False,
|
| 635 |
+
}
|
| 636 |
+
result = Records(
|
| 637 |
+
connector_id=self.id,
|
| 638 |
+
category=self.category,
|
| 639 |
+
state=State.CONNECTED,
|
| 640 |
+
records=[record],
|
| 641 |
+
source="CISA KEV + NIST NVD CVE 2.0 + FIRST EPSS",
|
| 642 |
+
live=True,
|
| 643 |
+
note=(
|
| 644 |
+
f"{coverage.lower()} official-source coverage · deterministic defensive "
|
| 645 |
+
"prioritization only · no exploit content or execution authority"
|
| 646 |
+
),
|
| 647 |
+
schema_preview=list(self.schema_preview),
|
| 648 |
+
)
|
| 649 |
+
_put(cache_key, result)
|
| 650 |
+
return result
|
| 651 |
+
|
| 652 |
+
|
| 653 |
__all__ = ["CisaKevConnector", "NvdCveConnector", "EpssConnector",
|
| 654 |
+
"MitreAttackConnector", "GithubConnector",
|
| 655 |
+
"DefensiveFusionConnector"]
|