#!/usr/bin/env python3 """Agent for prioritizing vulnerabilities with CVSS scoring. Calculates CVSS v3.1 base scores from metric vectors, enriches with EPSS exploit probability and KEV catalog data, and generates a risk-prioritized remediation report. """ import json import requests from datetime import datetime from collections import defaultdict CVSS_WEIGHTS = { "AV": {"N": 0.85, "A": 0.62, "L": 0.55, "P": 0.20}, "AC": {"L": 0.77, "H": 0.44}, "PR": {"N": {"U": 0.85, "C": 0.85}, "L": {"U": 0.62, "C": 0.68}, "H": {"U": 0.27, "C": 0.50}}, "UI": {"N": 0.85, "R": 0.62}, "S": {"U": "unchanged", "C": "changed"}, "C": {"H": 0.56, "L": 0.22, "N": 0.0}, "I": {"H": 0.56, "L": 0.22, "N": 0.0}, "A": {"H": 0.56, "L": 0.22, "N": 0.0}, } class CVSSPrioritizationAgent: """Calculates CVSS scores and prioritizes vulnerabilities.""" def __init__(self): self.vulnerabilities = [] def parse_vector(self, vector_string): """Parse CVSS v3.1 vector string into metric dict.""" metrics = {} parts = vector_string.replace("CVSS:3.1/", "").split("/") for part in parts: key, val = part.split(":") metrics[key] = val return metrics def calculate_base_score(self, vector_string): """Calculate CVSS v3.1 base score from vector string.""" m = self.parse_vector(vector_string) scope_changed = m.get("S") == "C" isc_base = 1 - ( (1 - CVSS_WEIGHTS["C"][m["C"]]) * (1 - CVSS_WEIGHTS["I"][m["I"]]) * (1 - CVSS_WEIGHTS["A"][m["A"]]) ) if scope_changed: impact = 7.52 * (isc_base - 0.029) - 3.25 * (isc_base - 0.02) ** 15 else: impact = 6.42 * isc_base if impact <= 0: return 0.0 scope_key = "C" if scope_changed else "U" pr_val = CVSS_WEIGHTS["PR"][m["PR"]][scope_key] exploitability = (8.22 * CVSS_WEIGHTS["AV"][m["AV"]] * CVSS_WEIGHTS["AC"][m["AC"]] * pr_val * CVSS_WEIGHTS["UI"][m["UI"]]) if scope_changed: score = min(1.08 * (impact + exploitability), 10.0) else: score = min(impact + exploitability, 10.0) import math return math.ceil(score * 10) / 10 def severity_rating(self, score): if score == 0.0: return "None" elif score <= 3.9: return "Low" elif score <= 6.9: return "Medium" elif score <= 8.9: return "High" return "Critical" def fetch_epss(self, cve_ids): """Fetch EPSS exploit probability scores from FIRST.org API.""" scores = {} try: cves = ",".join(cve_ids[:100]) resp = requests.get( f"https://api.first.org/data/v1/epss?cve={cves}", timeout=15) if resp.status_code == 200: for entry in resp.json().get("data", []): scores[entry["cve"]] = { "epss": float(entry.get("epss", 0)), "percentile": float(entry.get("percentile", 0)), } except requests.RequestException: pass return scores def fetch_kev(self): """Fetch CISA Known Exploited Vulnerabilities catalog.""" try: resp = requests.get( "https://www.cisa.gov/sites/default/files/feeds/" "known_exploited_vulnerabilities.json", timeout=15) if resp.status_code == 200: return {v["cveID"] for v in resp.json().get("vulnerabilities", [])} except requests.RequestException: pass return set() def add_vulnerability(self, cve_id, vector, description=""): score = self.calculate_base_score(vector) self.vulnerabilities.append({ "cve_id": cve_id, "vector": vector, "cvss_score": score, "severity": self.severity_rating(score), "description": description, }) def prioritize(self): """Enrich and prioritize all vulnerabilities.""" cve_ids = [v["cve_id"] for v in self.vulnerabilities] epss_data = self.fetch_epss(cve_ids) kev_set = self.fetch_kev() for vuln in self.vulnerabilities: cve = vuln["cve_id"] epss = epss_data.get(cve, {}) vuln["epss_score"] = epss.get("epss", 0) vuln["epss_percentile"] = epss.get("percentile", 0) vuln["in_kev"] = cve in kev_set priority = vuln["cvss_score"] * 10 if vuln["in_kev"]: priority += 30 if vuln["epss_score"] > 0.5: priority += 20 elif vuln["epss_score"] > 0.1: priority += 10 vuln["priority_score"] = round(priority, 1) self.vulnerabilities.sort(key=lambda v: v["priority_score"], reverse=True) return self.vulnerabilities def generate_report(self): self.prioritize() sev_dist = defaultdict(int) for v in self.vulnerabilities: sev_dist[v["severity"]] += 1 report = { "report_date": datetime.utcnow().isoformat(), "total_vulns": len(self.vulnerabilities), "severity_distribution": dict(sev_dist), "kev_count": sum(1 for v in self.vulnerabilities if v["in_kev"]), "prioritized_vulns": self.vulnerabilities, } print(json.dumps(report, indent=2)) return report def main(): agent = CVSSPrioritizationAgent() agent.add_vulnerability("CVE-2024-3400", "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H") agent.add_vulnerability("CVE-2024-21887", "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H") agent.add_vulnerability("CVE-2023-44487", "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H") agent.generate_report() if __name__ == "__main__": main()