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
|
def calculate_priority_score(finding, epss_data, kev_set, cmdb):
cve = finding['cve']
cvss = finding['cvss_v3']
epss = epss_data.get(cve, {}).get('epss', 0)
kev_bonus = 30 if cve in kev_set else 0
asset_crit = get_asset_criticality(finding['asset_hostname'], finding['asset_ip'])
score = (cvss * 0.4) + (epss * 100 * 0.3) + (kev_bonus * 0.2) + (asset_crit * 0.1)
return round(score, 2)
def score_to_priority(score):
if score >= 80: return 'P1', 'Critical', '72 hours'
if score >= 60: return 'P2', 'High', '7 days'
if score >= 40: return 'P3', 'Medium', '30 days'
return 'P4', 'Low', '90 days'
def create_patch_ticket(finding, score, sn_client):
priority, severity, sla = score_to_priority(score)
cve = finding['cve']
is_kev = is_in_kev(cve)
description = f"""
**CVE:** {cve}
**CVSS v3:** {finding['cvss_v3']}
**EPSS:** {finding.get('epss', 0):.2%} probability of exploitation
**CISA KEV:** {'YES — actively exploited in the wild' if is_kev else 'No'}
**Asset:** {finding['asset_hostname']} ({finding['asset_ip']})
**Asset Criticality:** {get_asset_criticality(finding['asset_hostname'], finding['asset_ip'])}/10
**Priority Score:** {score}
**SLA:** Remediate within {sla}
**Remediation Steps:**
{get_remediation_guidance(cve)}
"""
return sn_client.create_incident(
priority=priority[1],
short_desc=f"[{priority}] Patch required: {cve} on {finding['asset_hostname']}",
description=description,
assignment_group='Patch Management Team',
due_date=calculate_due_date(sla)
)
|