Lesson 1 of 1 · 20 min read

Vulnerability Intelligence — Beyond CVSS to Exploitation Reality

Vulnerability intelligence is not vulnerability scanning — it is the analysis that answers “which of these vulnerabilities actually matters to us right now?”


Vulnerability Prioritization Framework

VULNERABILITY PRIORITIZATION METHODOLOGY
=========================================

INPUT: 847 vulnerabilities (CVSS 7.0+)
GOAL: Identify top 50 for immediate patching

PASS 1 — Confirmed exploitation filter (binary — include/exclude)
  Check each CVE against CISA KEV catalog:
    → KEV hit = automatic top-50 candidate regardless of CVSS
  Check each CVE against EPSS:
    → EPSS > 0.50 (50% exploitation probability in 30 days) = top-50 candidate
  Result: likely 20-80 CVEs pass this filter (varies by environment)

PASS 2 — Threat actor relevance filter
  For each remaining CVE:
    → Has any threat actor targeting our sector exploited this CVE?
    → Sources: vendor reports, CISA advisories, ISAC bulletins, threat actor profiles
  Result: CVEs with actor attribution + organizational relevance elevated to top priority

PASS 3 — Asset criticality filter
  For each remaining CVE:
    → What asset is vulnerable? (internet-facing vs. internal vs. non-critical)
    → Internet-facing assets: elevated priority
    → Assets processing PII, financial data, or intellectual property: elevated
    → End-of-life systems that cannot be patched: document separately for risk acceptance
  Result: same CVE in internet-facing VPN vs. air-gapped lab = very different priority

PASS 4 — Exploitability in environment filter
  For each remaining CVE:
    → Is the exploitation condition met in our environment?
    → Auth required: do external users have valid credentials? 
    → Adjacent network access required: is the service network-reachable from expected attacker vantage?
  Result: narrows further based on realistic exploitation path

FINAL RANKING:
  Priority 1: KEV + EPSS>0.50 + internet-facing + actor-relevant = EMERGENCY PATCH (this week)
  Priority 2: EPSS>0.20 + actor-relevant + critical asset = URGENT (this sprint)
  Priority 3: EPSS>0.05 + internet-facing = STANDARD (this quarter)
  Priority 4: Everything else = SCHEDULED (next quarter or risk-accept)

OUTPUT: Ranked list with CVSS, EPSS, KEV status, exploiting actor, affected asset tier

EPSS and KEV Data Access

# Pull EPSS scores from FIRST API
import requests
import json

def get_epss_scores(cve_list):
    """Fetch EPSS scores for a list of CVEs"""
    # EPSS API - free, no key required
    cve_param = ','.join(cve_list)
    url = f"https://api.first.org/data/v1/epss?cve={cve_param}"
    
    response = requests.get(url)
    data = response.json()
    
    results = {}
    for item in data['data']:
        results[item['cve']] = {
            'epss': float(item['epss']),
            'percentile': float(item['percentile']),
            'date': item['date']
        }
    return results

# Pull CISA KEV catalog
def get_kev_catalog():
    """Download the full CISA KEV catalog"""
    url = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
    response = requests.get(url)
    kev_data = response.json()
    
    kev_cves = {v['cveID']: v for v in kev_data['vulnerabilities']}
    return kev_cves

# Prioritization analysis
def prioritize_vulnerabilities(vuln_list):
    """
    vuln_list: list of dicts with at least 'cve_id', 'cvss_score', 'asset_tier'
    asset_tier: 1=internet-facing, 2=internal-critical, 3=internal-standard
    """
    kev = get_kev_catalog()
    cve_ids = [v['cve_id'] for v in vuln_list]
    epss = get_epss_scores(cve_ids)
    
    prioritized = []
    for vuln in vuln_list:
        cve = vuln['cve_id']
        score = {
            'cve': cve,
            'cvss': vuln['cvss_score'],
            'epss': epss.get(cve, {}).get('epss', 0),
            'in_kev': cve in kev,
            'kev_due_date': kev.get(cve, {}).get('dueDate', None),
            'asset_tier': vuln['asset_tier'],
        }
        
        # Calculate priority score
        priority = 0
        if score['in_kev']:
            priority += 100  # KEV = always high priority
        priority += score['epss'] * 50  # 0-50 points for exploitation probability
        priority += (4 - score['asset_tier']) * 20  # 20 points for internet-facing
        
        score['priority_score'] = priority
        prioritized.append(score)
    
    return sorted(prioritized, key=lambda x: x['priority_score'], reverse=True)

# Example output format for CTI vulnerability advisory
def format_advisory(prioritized_vulns, top_n=50):
    print(f"VULNERABILITY PRIORITY ADVISORY — TOP {top_n}")
    print(f"{'CVE':<20} {'CVSS':<6} {'EPSS':<6} {'KEV':<5} {'Asset':<8} {'Priority'}")
    print("-" * 60)
    for v in prioritized_vulns[:top_n]:
        kev_str = "YES" if v['in_kev'] else "no"
        print(f"{v['cve']:<20} {v['cvss']:<6.1f} {v['epss']:<6.2f} {kev_str:<5} {'Tier '+str(v['asset_tier']):<8} {v['priority_score']:.0f}")