Files
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands
- Fix 49 verify=False in defensive skills (env-var override)
- Add timeout to 231 HTTP/subprocess/socket calls
- Fix 6 SQL injection patterns with whitelist validation
- Replace 8 __import__() with standard imports
- Remove 701 unused imports across 442 files
- Add authorized-testing disclaimers to all offensive skills
- Complete 11 incomplete skill directories
- Expand 10 stub SKILL.md files with full content
- Fix 2 YAML parse errors in frontmatter
- Fix 5 pre-existing syntax errors
- Convert 22 hardcoded paths/ports to environment variables
- Back up 21 redundant skill pairs to .bak
- Fix 2 global declaration errors
- 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE)
- 0 compile errors across all 724 agent.py files
2026-03-19 13:26:49 +01:00

176 lines
5.9 KiB
Python

#!/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()