vulnerability management

Implementing Vulnerability Remediation SLA

Vulnerability remediation SLAs define mandatory timeframes for patching or mitigating identified vulnerabilities based on severity, asset criticality, and exploit availability. Effective SLA programs drive accountability, ensure consistent remediation timelines, and provide measurable KPIs for vulnerability management maturity.

cvepatch-managementremediationriskslavulnerability-management
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Vulnerability remediation SLAs define mandatory timeframes for patching or mitigating identified vulnerabilities based on severity, asset criticality, and exploit availability. Effective SLA programs drive accountability, ensure consistent remediation timelines, and provide measurable KPIs for vulnerability management maturity.

When to Use

  • When deploying or configuring implementing vulnerability remediation sla capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • Vulnerability scanning program producing regular findings
  • Asset inventory with criticality classifications
  • Ticketing system (Jira, ServiceNow, etc.) for remediation tracking
  • Executive sponsorship for SLA enforcement
  • Cross-functional agreement from IT operations, development, and security

Core Concepts

SLA Framework Components

  1. Severity Classification: CVSS base score + threat context (EPSS, KEV)
  2. Asset Tiering: Business criticality and exposure level
  3. Remediation Timeframes: Maximum days to remediate by category
  4. Exception Process: Documented approval for SLA extensions
  5. Escalation Procedures: Actions when SLAs are breached
  6. Metrics and Reporting: KPIs for compliance tracking

Recommended SLA Matrix

Severity Tier 1 (Critical) Tier 2 (Important) Tier 3 (Standard)
Critical (CVSS 9.0-10.0) 24-48 hours 72 hours 7 days
High (CVSS 7.0-8.9) 7 days 14 days 30 days
Medium (CVSS 4.0-6.9) 30 days 45 days 60 days
Low (CVSS 0.1-3.9) 90 days 90 days 90 days
CISA KEV Listed 24 hours 48 hours 7 days

SLA Accelerators (Reduce SLA by 50%)

  • Exploit code publicly available
  • Active exploitation observed in the wild (CISA KEV)
  • Internet-facing asset affected
  • EPSS score > 0.5 (50% exploitation probability)
  • Previous breach via similar vulnerability type

Workflow

Step 1: Define Asset Tiers

Tier 1 (Critical Assets):
- Customer-facing production systems
- Payment processing infrastructure
- Domain controllers and identity systems
- Core network infrastructure (firewalls, routers)
- Databases containing PII/PHI/PCI data
 
Tier 2 (Important Assets):
- Internal production applications
- Email and collaboration systems
- Development/staging environments with production data
- Backup and recovery infrastructure
- VPN and remote access gateways
 
Tier 3 (Standard Assets):
- End-user workstations
- Development/test environments
- Print servers and peripheral management
- Non-critical internal tools

Step 2: Establish SLA Policy Document

Key sections to include:

  • Purpose and scope
  • Roles and responsibilities (RACI matrix)
  • Severity definitions and calculation method
  • Remediation timeframes by severity and asset tier
  • Exception request process and approval authority
  • Escalation procedures for SLA breaches
  • Metrics, reporting cadence, and governance
  • Policy review and update schedule

Step 3: Integrate with Ticketing System

# ServiceNow / Jira integration for automatic ticket creation
# See process.py for full implementation
 
# Key fields for remediation tickets:
# - Vulnerability ID (CVE/Plugin ID)
# - Affected host(s)
# - Severity (CVSS + contextual factors)
# - Asset tier
# - SLA deadline (calculated from discovery date)
# - Assignment group
# - Remediation instructions
# - Verification criteria

Step 4: Configure Escalation Chain

SLA Status          Action                          Notify
───────────────────────────────────────────────────────────
75% elapsed         Warning email                   Asset owner
100% elapsed        SLA breach notification          Manager + CISO
100% + 7 days       Executive escalation             VP/CTO
100% + 30 days      Risk acceptance required          CISO approval
100% + 90 days      Compensating controls mandatory   Board report

Step 5: Establish Exception Process

Valid exception reasons:

  • System cannot be patched without major downtime (scheduled maintenance window)
  • No vendor patch available (apply compensating controls)
  • Patch breaks critical functionality (require test results as evidence)
  • End-of-life system pending decommission (document risk acceptance)

Exception requirements:

  • Written justification with business impact
  • Compensating controls documented and implemented
  • Approved by asset owner AND security leadership
  • Maximum exception duration: 90 days (renewable with re-approval)
  • Tracked in vulnerability management platform

Key Performance Indicators (KPIs)

Primary Metrics

KPI Definition Target
SLA Compliance Rate % of vulns remediated within SLA >90%
Mean Time to Remediate (MTTR) Average days from discovery to fix Critical: <3d, High: <10d
Vulnerability Backlog Open vulnerabilities past SLA <5% of total
Exception Rate % of findings with active exceptions <10%
Recurrence Rate % of vulns that reappear after remediation <5%

Trending Metrics

  • Month-over-month SLA compliance trend
  • MTTR trend by severity
  • Vulnerability density per asset (vulns/host)
  • Patch coverage rate (% of assets scanned and compliant)
  • Time to first response (acknowledgment of finding)

Best Practices

  1. Start with achievable SLAs and tighten over time as maturity improves
  2. Use automated ticketing to eliminate manual SLA tracking
  3. Provide remediation teams with clear fix instructions, not just CVE numbers
  4. Track SLA compliance at the team/department level for accountability
  5. Report SLA metrics to executive leadership monthly
  6. Include compensating controls as valid interim remediation
  7. Align SLAs with regulatory requirements (PCI DSS, HIPAA, SOX)
  8. Review and adjust SLAs annually based on threat landscape changes

Common Pitfalls

  • Setting unrealistic SLAs that teams cannot meet (creates SLA fatigue)
  • No executive enforcement of SLA breaches
  • Treating all assets equally without tiering
  • Not accounting for vulnerability context (EPSS, KEV) in SLA calculation
  • Missing exception management process (leads to untracked risk)
  • Measuring only compliance rate without analyzing root causes of breaches
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md4.7 KB

API Reference: Vulnerability Remediation SLA Tracking

Libraries Used

Library Purpose
requests Fetch vulnerability data from scanner APIs
json Parse vulnerability and asset data
datetime Calculate SLA deadlines, time-to-remediation
csv Export SLA compliance reports

Installation

pip install requests

SLA Tiers

Severity CVSS Range SLA Deadline Description
Critical 9.0 - 10.0 24 hours Actively exploited or trivially exploitable
High 7.0 - 8.9 72 hours Remote code execution, privilege escalation
Medium 4.0 - 6.9 30 days Requires user interaction or local access
Low 0.1 - 3.9 90 days Informational, minimal impact

Core Operations

Define SLA Configuration

from datetime import datetime, timedelta
 
SLA_TIERS = {
    "critical": timedelta(hours=24),
    "high": timedelta(hours=72),
    "medium": timedelta(days=30),
    "low": timedelta(days=90),
}
 
def get_sla_deadline(severity, discovery_date):
    tier = severity.lower()
    sla_window = SLA_TIERS.get(tier, timedelta(days=90))
    return discovery_date + sla_window

Calculate SLA Status for a Vulnerability

def calculate_sla_status(vuln):
    discovery = datetime.fromisoformat(vuln["discovery_date"])
    deadline = get_sla_deadline(vuln["severity"], discovery)
    now = datetime.now()
 
    if vuln.get("remediated_date"):
        remediated = datetime.fromisoformat(vuln["remediated_date"])
        return {
            "cve": vuln["cve"],
            "status": "remediated",
            "met_sla": remediated <= deadline,
            "time_to_remediate_hours": (remediated - discovery).total_seconds() / 3600,
        }
 
    overdue = now > deadline
    hours_remaining = (deadline - now).total_seconds() / 3600 if not overdue else 0
    hours_overdue = (now - deadline).total_seconds() / 3600 if overdue else 0
 
    return {
        "cve": vuln["cve"],
        "status": "overdue" if overdue else "open",
        "severity": vuln["severity"],
        "deadline": deadline.isoformat(),
        "hours_remaining": round(hours_remaining, 1),
        "hours_overdue": round(hours_overdue, 1),
    }

Fetch Vulnerabilities from Tenable

import requests
import os
 
TENABLE_URL = "https://cloud.tenable.com"
headers = {
    "X-ApiKeys": f"accessKey={os.environ['TENABLE_ACCESS_KEY']};secretKey={os.environ['TENABLE_SECRET_KEY']}",
}
 
def get_open_vulnerabilities():
    resp = requests.get(
        f"{TENABLE_URL}/workbenches/vulnerabilities",
        headers=headers,
        params={"date_range": 90, "filter.0.filter": "severity", "filter.0.value": "4,3"},
        timeout=60,
    )
    resp.raise_for_status()
    return resp.json().get("vulnerabilities", [])

Generate SLA Compliance Report

def generate_sla_report(vulnerabilities):
    report = {
        "total": len(vulnerabilities),
        "by_status": {"open": 0, "overdue": 0, "remediated": 0},
        "by_severity": {"critical": 0, "high": 0, "medium": 0, "low": 0},
        "sla_compliance_rate": 0.0,
        "overdue_vulns": [],
        "mean_time_to_remediate": {},
    }
 
    remediated_times = {"critical": [], "high": [], "medium": [], "low": []}
 
    for vuln in vulnerabilities:
        status = calculate_sla_status(vuln)
        report["by_status"][status["status"]] += 1
        report["by_severity"][vuln["severity"].lower()] += 1
 
        if status["status"] == "overdue":
            report["overdue_vulns"].append(status)
        if status["status"] == "remediated":
            sev = vuln["severity"].lower()
            remediated_times[sev].append(status["time_to_remediate_hours"])
 
    total_with_deadline = report["by_status"]["remediated"] + report["by_status"]["overdue"]
    if total_with_deadline > 0:
        met_sla = sum(1 for v in vulnerabilities
                      if calculate_sla_status(v).get("met_sla", False))
        report["sla_compliance_rate"] = round(met_sla / total_with_deadline * 100, 1)
 
    for sev, times in remediated_times.items():
        if times:
            report["mean_time_to_remediate"][sev] = round(sum(times) / len(times), 1)
 
    return report

Output Format

{
  "report_date": "2025-01-15",
  "total": 245,
  "by_status": {"open": 180, "overdue": 23, "remediated": 42},
  "by_severity": {"critical": 5, "high": 28, "medium": 112, "low": 100},
  "sla_compliance_rate": 87.5,
  "mean_time_to_remediate": {
    "critical": 18.5,
    "high": 52.3,
    "medium": 480.0,
    "low": 1200.0
  },
  "overdue_vulns": [
    {
      "cve": "CVE-2024-21887",
      "severity": "critical",
      "hours_overdue": 48.5,
      "deadline": "2025-01-13T10:00:00"
    }
  ]
}
standards.md1.1 KB

Standards and References - Vulnerability Remediation SLA

Regulatory SLA Requirements

  • PCI DSS v4.0 Req 6.3.3: Address vulnerabilities by risk ranking (critical/high within 30 days)
  • CISA BOD 22-01: Federal agencies must remediate KEV within specified timeframes
  • NIST SP 800-40 Rev 4: Enterprise Patch Management Planning
  • SOX: Timely remediation of IT control deficiencies
  • HIPAA: Reasonable and appropriate security measures including patching

Industry Benchmarks

Severity CISA BOD 22-01 PCI DSS CIS Benchmark Best Practice
Critical 14 days (KEV) 30 days 48 hours 24-48 hours
High N/A 30 days 7 days 7-14 days
Medium N/A 90 days 30 days 30 days
Low N/A Next cycle 90 days 90 days

KPI Benchmarks (Industry Average)

Metric Average Top Quartile Best in Class
SLA Compliance 65% 85% >95%
MTTR (Critical) 15 days 5 days <2 days
MTTR (High) 30 days 14 days <7 days
Vuln Backlog 25% 10% <5%
workflows.md1.5 KB

Workflows - Vulnerability Remediation SLA

Workflow 1: SLA Assignment and Tracking

Vulnerability Discovered

    ├──> Determine Severity (CVSS + EPSS + KEV)
    ├──> Determine Asset Tier (CMDB lookup)
    ├──> Calculate SLA Deadline

    ├──> Create Remediation Ticket (Auto)
    │       ├──> Assign to responsible team
    │       ├──> Set SLA deadline
    │       └──> Include remediation instructions

    ├──> Monitor Progress
    │       ├──> 50% elapsed: Status check
    │       ├──> 75% elapsed: Warning notification
    │       └──> 100% elapsed: Breach escalation

    └──> Verify Remediation
            ├──> Re-scan target
            ├──> Confirm vulnerability resolved
            └──> Close ticket

Workflow 2: SLA Breach Escalation

SLA Breached (100% elapsed)

    ├──> Day 0: Auto-notify asset owner + manager
    ├──> Day 7: Escalate to department head
    ├──> Day 14: Escalate to CISO
    ├──> Day 30: Require formal risk acceptance
    └──> Day 90: Report to executive committee

Workflow 3: Exception Management

Exception Request Submitted

    ├──> Validate justification
    ├──> Verify compensating controls
    ├──> Risk assessment review

    ├──> Approved → Set new deadline, document in system
    └──> Denied → Original SLA enforced, escalate

Scripts 2

agent.py8.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Vulnerability remediation SLA tracking agent.

Tracks vulnerability remediation against defined SLA targets based on
severity. Ingests vulnerability data from scanners (JSON/CSV format),
calculates SLA compliance, identifies overdue items, and generates
remediation priority reports.
"""
import argparse
import csv
import json
import os
import sys
from datetime import datetime, timezone, timedelta


DEFAULT_SLA_DAYS = {
    "CRITICAL": 7,
    "HIGH": 30,
    "MEDIUM": 90,
    "LOW": 180,
}


def load_vulnerabilities(source_path):
    """Load vulnerabilities from a JSON or CSV file."""
    ext = os.path.splitext(source_path)[1].lower()
    if ext == ".json":
        with open(source_path, "r") as f:
            data = json.load(f)
        if isinstance(data, list):
            return data
        return data.get("vulnerabilities", data.get("findings", data.get("results", [])))
    elif ext == ".csv":
        vulns = []
        with open(source_path, "r", newline="") as f:
            reader = csv.DictReader(f)
            for row in reader:
                vulns.append(row)
        return vulns
    else:
        print(f"[!] Unsupported file format: {ext}", file=sys.stderr)
        return []


def normalize_vulnerability(vuln):
    """Normalize vulnerability fields from various scanner formats."""
    return {
        "id": (vuln.get("id") or vuln.get("vulnerability_id") or
               vuln.get("cve_id") or vuln.get("CVE") or vuln.get("plugin_id") or "unknown"),
        "severity": (vuln.get("severity") or vuln.get("risk") or
                     vuln.get("Severity") or "MEDIUM").upper(),
        "title": (vuln.get("title") or vuln.get("name") or
                  vuln.get("vulnerability_name") or vuln.get("Title") or "Unknown"),
        "asset": (vuln.get("asset") or vuln.get("host") or
                  vuln.get("ip") or vuln.get("hostname") or "unknown"),
        "discovered_date": (vuln.get("discovered_date") or vuln.get("first_found") or
                           vuln.get("discovered") or vuln.get("date_found") or
                           datetime.now(timezone.utc).isoformat()),
        "status": (vuln.get("status") or vuln.get("state") or "open").lower(),
        "remediation": (vuln.get("remediation") or vuln.get("fix") or
                       vuln.get("solution") or ""),
    }


def calculate_sla_status(vulns, sla_days=None):
    """Calculate SLA compliance for each vulnerability."""
    if sla_days is None:
        sla_days = DEFAULT_SLA_DAYS

    now = datetime.now(timezone.utc)
    results = []

    for vuln in vulns:
        norm = normalize_vulnerability(vuln)
        if norm["status"] not in ("open", "new", "active", "unresolved"):
            norm["sla_status"] = "RESOLVED"
            norm["sla_days_remaining"] = None
            results.append(norm)
            continue

        severity = norm["severity"]
        target_days = sla_days.get(severity, sla_days.get("MEDIUM", 90))

        try:
            disc_str = norm["discovered_date"]
            if "T" in disc_str:
                discovered = datetime.fromisoformat(disc_str.replace("Z", "+00:00"))
            else:
                discovered = datetime.strptime(disc_str[:10], "%Y-%m-%d").replace(tzinfo=timezone.utc)
        except (ValueError, TypeError):
            discovered = now
            norm["parse_warning"] = "Could not parse discovered_date"

        age_days = (now - discovered).days
        sla_deadline = discovered + timedelta(days=target_days)
        days_remaining = (sla_deadline - now).days

        norm["age_days"] = age_days
        norm["sla_target_days"] = target_days
        norm["sla_deadline"] = sla_deadline.isoformat()
        norm["sla_days_remaining"] = days_remaining

        if days_remaining < 0:
            norm["sla_status"] = "BREACHED"
            norm["sla_overdue_days"] = abs(days_remaining)
        elif days_remaining <= 7:
            norm["sla_status"] = "AT_RISK"
        else:
            norm["sla_status"] = "ON_TRACK"

        results.append(norm)

    return results


def generate_metrics(results):
    """Generate SLA compliance metrics."""
    open_vulns = [r for r in results if r.get("sla_status") != "RESOLVED"]
    breached = [r for r in open_vulns if r.get("sla_status") == "BREACHED"]
    at_risk = [r for r in open_vulns if r.get("sla_status") == "AT_RISK"]
    on_track = [r for r in open_vulns if r.get("sla_status") == "ON_TRACK"]

    compliance_rate = ((len(on_track) + len(at_risk)) / len(open_vulns) * 100) if open_vulns else 100.0

    by_severity = {}
    for r in open_vulns:
        sev = r.get("severity", "MEDIUM")
        by_severity.setdefault(sev, {"total": 0, "breached": 0, "at_risk": 0})
        by_severity[sev]["total"] += 1
        if r.get("sla_status") == "BREACHED":
            by_severity[sev]["breached"] += 1
        elif r.get("sla_status") == "AT_RISK":
            by_severity[sev]["at_risk"] += 1

    oldest_breach = None
    if breached:
        oldest = max(breached, key=lambda r: r.get("sla_overdue_days", 0))
        oldest_breach = {
            "id": oldest["id"],
            "severity": oldest["severity"],
            "overdue_days": oldest.get("sla_overdue_days", 0),
            "asset": oldest["asset"],
        }

    return {
        "total_open": len(open_vulns),
        "breached": len(breached),
        "at_risk": len(at_risk),
        "on_track": len(on_track),
        "resolved": len(results) - len(open_vulns),
        "compliance_rate": round(compliance_rate, 1),
        "by_severity": by_severity,
        "oldest_breach": oldest_breach,
    }


def format_summary(metrics, results):
    """Print SLA tracking summary."""
    print(f"\n{'='*60}")
    print(f"  Vulnerability Remediation SLA Report")
    print(f"{'='*60}")
    print(f"  Open Vulnerabilities : {metrics['total_open']}")
    print(f"  SLA Breached         : {metrics['breached']}")
    print(f"  At Risk (<7 days)    : {metrics['at_risk']}")
    print(f"  On Track             : {metrics['on_track']}")
    print(f"  Resolved             : {metrics['resolved']}")
    print(f"  Compliance Rate      : {metrics['compliance_rate']}%")

    print(f"\n  By Severity:")
    for sev in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
        data = metrics["by_severity"].get(sev, {})
        if data.get("total", 0) > 0:
            print(f"    {sev:10s}: {data['total']} open, {data['breached']} breached, {data['at_risk']} at-risk")

    breached = [r for r in results if r.get("sla_status") == "BREACHED"]
    if breached:
        print(f"\n  SLA Breached ({len(breached)}):")
        for r in sorted(breached, key=lambda x: -x.get("sla_overdue_days", 0))[:15]:
            print(f"    [{r['severity']:8s}] {r['id']:20s} | {r['asset']:20s} | "
                  f"{r.get('sla_overdue_days', 0)}d overdue | {r['title'][:30]}")

    if metrics.get("oldest_breach"):
        ob = metrics["oldest_breach"]
        print(f"\n  Worst Breach: {ob['id']} ({ob['severity']}) on {ob['asset']} - "
              f"{ob['overdue_days']} days overdue")


def main():
    parser = argparse.ArgumentParser(description="Vulnerability remediation SLA tracking agent")
    parser.add_argument("--source", required=True, help="Vulnerability data file (JSON or CSV)")
    parser.add_argument("--sla-critical", type=int, default=7, help="SLA days for CRITICAL (default: 7)")
    parser.add_argument("--sla-high", type=int, default=30, help="SLA days for HIGH (default: 30)")
    parser.add_argument("--sla-medium", type=int, default=90, help="SLA days for MEDIUM (default: 90)")
    parser.add_argument("--sla-low", type=int, default=180, help="SLA days for LOW (default: 180)")
    parser.add_argument("--output", "-o", help="Output JSON report")
    parser.add_argument("--verbose", "-v", action="store_true")
    args = parser.parse_args()

    sla_days = {
        "CRITICAL": args.sla_critical,
        "HIGH": args.sla_high,
        "MEDIUM": args.sla_medium,
        "LOW": args.sla_low,
    }

    vulns = load_vulnerabilities(args.source)
    print(f"[*] Loaded {len(vulns)} vulnerabilities from {args.source}")

    results = calculate_sla_status(vulns, sla_days)
    metrics = generate_metrics(results)
    format_summary(metrics, results)

    report = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "tool": "Vulnerability SLA Tracker",
        "source": args.source,
        "sla_targets": sla_days,
        "metrics": metrics,
        "vulnerabilities": results,
    }

    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"\n[+] Report saved to {args.output}")
    elif args.verbose:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
process.py10.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Vulnerability Remediation SLA Tracking Engine

Calculates SLA deadlines, monitors compliance, generates breach
notifications, and produces executive reporting dashboards.

Requirements:
    pip install pandas jinja2

Usage:
    python process.py calculate --vulns vulns.csv --assets assets.csv --output sla_assignments.csv
    python process.py monitor --sla-csv sla_assignments.csv --report sla_report.html
"""

import argparse
import json
import sys
from datetime import datetime, timedelta

import pandas as pd


class SLACalculator:
    """Calculate remediation SLA deadlines based on severity and asset tier."""

    DEFAULT_SLA_MATRIX = {
        ("Critical", "Tier1"): 2,
        ("Critical", "Tier2"): 3,
        ("Critical", "Tier3"): 7,
        ("High", "Tier1"): 7,
        ("High", "Tier2"): 14,
        ("High", "Tier3"): 30,
        ("Medium", "Tier1"): 30,
        ("Medium", "Tier2"): 45,
        ("Medium", "Tier3"): 60,
        ("Low", "Tier1"): 90,
        ("Low", "Tier2"): 90,
        ("Low", "Tier3"): 90,
    }

    SLA_ACCELERATORS = {
        "in_cisa_kev": 0.5,
        "exploit_available": 0.5,
        "internet_facing": 0.5,
        "epss_high": 0.5,
    }

    def __init__(self, sla_matrix: dict = None):
        self.sla_matrix = sla_matrix or self.DEFAULT_SLA_MATRIX

    def get_severity_label(self, cvss_score: float) -> str:
        """Map CVSS score to severity label."""
        if cvss_score >= 9.0:
            return "Critical"
        elif cvss_score >= 7.0:
            return "High"
        elif cvss_score >= 4.0:
            return "Medium"
        elif cvss_score > 0:
            return "Low"
        return "Info"

    def calculate_sla(self, severity: str, tier: str, accelerators: dict = None) -> int:
        """Calculate SLA days based on severity, tier, and accelerators."""
        base_sla = self.sla_matrix.get((severity, tier), 90)

        if accelerators:
            for accel, factor in self.SLA_ACCELERATORS.items():
                if accelerators.get(accel, False):
                    base_sla = int(base_sla * factor)

        return max(base_sla, 1)

    def assign_slas(self, vulns_df: pd.DataFrame, assets_df: pd.DataFrame) -> pd.DataFrame:
        """Assign SLA deadlines to all vulnerabilities."""
        merged = vulns_df.merge(
            assets_df[["hostname", "tier", "internet_facing"]],
            on="hostname", how="left"
        )

        results = []
        for _, row in merged.iterrows():
            severity = row.get("severity", self.get_severity_label(float(row.get("cvss_score", 0))))
            tier = row.get("tier", "Tier3")

            accelerators = {
                "in_cisa_kev": row.get("in_cisa_kev", False),
                "exploit_available": row.get("exploit_available", False),
                "internet_facing": row.get("internet_facing", False),
                "epss_high": float(row.get("epss_score", 0)) > 0.5,
            }

            sla_days = self.calculate_sla(severity, tier, accelerators)
            discovery_date = pd.to_datetime(row.get("discovery_date", datetime.now()))
            deadline = discovery_date + timedelta(days=sla_days)

            results.append({
                **row.to_dict(),
                "severity": severity,
                "sla_days": sla_days,
                "discovery_date": discovery_date.isoformat(),
                "sla_deadline": deadline.isoformat(),
                "days_remaining": (deadline - datetime.now()).days,
                "sla_status": self._get_sla_status(deadline, row.get("remediated_date")),
            })

        return pd.DataFrame(results)

    def _get_sla_status(self, deadline: datetime, remediated_date=None) -> str:
        """Determine SLA status."""
        now = datetime.now()
        if remediated_date and pd.notna(remediated_date):
            rem_date = pd.to_datetime(remediated_date)
            if isinstance(deadline, str):
                deadline = pd.to_datetime(deadline)
            return "compliant" if rem_date <= deadline else "breached_remediated"

        if isinstance(deadline, str):
            deadline = pd.to_datetime(deadline)

        days_remaining = (deadline - now).days
        if days_remaining < 0:
            return "breached"
        elif days_remaining <= 3:
            return "critical"
        elif days_remaining <= 7:
            return "warning"
        return "on_track"


class SLAMonitor:
    """Monitor SLA compliance and generate reports."""

    def __init__(self, sla_df: pd.DataFrame):
        self.sla_df = sla_df

    def get_compliance_summary(self) -> dict:
        """Calculate overall SLA compliance metrics."""
        total = len(self.sla_df)
        status_counts = self.sla_df["sla_status"].value_counts().to_dict()

        compliant = status_counts.get("compliant", 0) + status_counts.get("on_track", 0)
        breached = status_counts.get("breached", 0) + status_counts.get("breached_remediated", 0)
        warning = status_counts.get("warning", 0) + status_counts.get("critical", 0)

        remediated = self.sla_df[self.sla_df["sla_status"].isin(["compliant", "breached_remediated"])]
        if not remediated.empty:
            mttr_data = remediated.copy()
            mttr_data["disc"] = pd.to_datetime(mttr_data["discovery_date"])
            mttr_data["rem"] = pd.to_datetime(mttr_data.get("remediated_date", datetime.now()))
            avg_mttr = (mttr_data["rem"] - mttr_data["disc"]).dt.days.mean()
        else:
            avg_mttr = 0

        return {
            "total_vulns": total,
            "compliant": compliant,
            "compliance_rate": f"{compliant / max(total, 1) * 100:.1f}%",
            "breached": breached,
            "breach_rate": f"{breached / max(total, 1) * 100:.1f}%",
            "at_risk": warning,
            "avg_mttr_days": round(avg_mttr, 1),
            "by_severity": self.sla_df.groupby("severity")["sla_status"].value_counts().to_dict(),
        }

    def get_breach_list(self) -> pd.DataFrame:
        """Get list of SLA-breached vulnerabilities."""
        return self.sla_df[self.sla_df["sla_status"] == "breached"].sort_values("days_remaining")

    def generate_report(self, output_path: str):
        """Generate SLA compliance HTML report."""
        summary = self.get_compliance_summary()
        breaches = self.get_breach_list().head(30)

        by_sev = self.sla_df.groupby("severity").agg(
            total=("sla_status", "count"),
            compliant=("sla_status", lambda x: (x.isin(["compliant", "on_track"])).sum()),
            breached=("sla_status", lambda x: (x.isin(["breached", "breached_remediated"])).sum()),
        ).reset_index()
        by_sev["rate"] = (by_sev["compliant"] / by_sev["total"] * 100).round(1)

        html = f"""<!DOCTYPE html>
<html>
<head>
    <title>SLA Compliance Dashboard - {datetime.now().strftime('%Y-%m-%d')}</title>
    <style>
        body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
        .header {{ background: #0f3460; color: white; padding: 20px; border-radius: 8px; }}
        .metrics {{ display: flex; gap: 15px; margin: 20px 0; flex-wrap: wrap; }}
        .card {{ background: white; padding: 20px; border-radius: 8px; flex: 1; min-width: 180px;
                 box-shadow: 0 2px 4px rgba(0,0,0,0.1); text-align: center; }}
        .card h3 {{ margin: 0; font-size: 2em; }}
        .green {{ border-top: 4px solid #27ae60; }}
        .red {{ border-top: 4px solid #e74c3c; }}
        .yellow {{ border-top: 4px solid #f39c12; }}
        table {{ width: 100%; border-collapse: collapse; background: white; margin: 15px 0;
                 box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        th {{ background: #2c3e50; color: white; padding: 10px; text-align: left; }}
        td {{ padding: 8px 10px; border-bottom: 1px solid #eee; }}
    </style>
</head>
<body>
    <div class="header">
        <h1>Vulnerability Remediation SLA Dashboard</h1>
        <p>Report Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}</p>
    </div>
    <div class="metrics">
        <div class="card green"><h3>{summary['compliance_rate']}</h3><p>SLA Compliance</p></div>
        <div class="card red"><h3>{summary['breached']}</h3><p>SLA Breaches</p></div>
        <div class="card yellow"><h3>{summary['at_risk']}</h3><p>At Risk</p></div>
        <div class="card"><h3>{summary['avg_mttr_days']}d</h3><p>Avg MTTR</p></div>
    </div>

    <h2>Compliance by Severity</h2>
    <table>
        <tr><th>Severity</th><th>Total</th><th>Compliant</th><th>Breached</th><th>Rate</th></tr>
        {''.join(f"<tr><td>{r.severity}</td><td>{r.total}</td><td>{r.compliant}</td><td>{r.breached}</td><td>{r.rate}%</td></tr>" for r in by_sev.itertuples())}
    </table>

    <h2>Active SLA Breaches (Top 30)</h2>
    <table>
        <tr><th>Host</th><th>CVE</th><th>Severity</th><th>SLA Days</th><th>Days Overdue</th></tr>
        {''.join(f"<tr><td>{r.hostname if hasattr(r,'hostname') else ''}</td><td>{r.cve if hasattr(r,'cve') else ''}</td><td>{r.severity}</td><td>{r.sla_days}</td><td>{abs(r.days_remaining)}</td></tr>" for r in breaches.itertuples())}
    </table>
</body>
</html>"""

        with open(output_path, "w", encoding="utf-8") as f:
            f.write(html)
        print(f"[+] SLA report saved to: {output_path}")


def main():
    parser = argparse.ArgumentParser(description="Vulnerability Remediation SLA Engine")
    subparsers = parser.add_subparsers(dest="command")

    calc_p = subparsers.add_parser("calculate", help="Assign SLA deadlines")
    calc_p.add_argument("--vulns", required=True, help="Vulnerabilities CSV")
    calc_p.add_argument("--assets", required=True, help="Assets CSV")
    calc_p.add_argument("--output", required=True, help="Output SLA CSV")

    mon_p = subparsers.add_parser("monitor", help="Monitor SLA compliance")
    mon_p.add_argument("--sla-csv", required=True, help="SLA assignments CSV")
    mon_p.add_argument("--report", default="sla_report.html", help="HTML report output")

    args = parser.parse_args()

    if args.command == "calculate":
        calc = SLACalculator()
        vulns = pd.read_csv(args.vulns)
        assets = pd.read_csv(args.assets)
        result = calc.assign_slas(vulns, assets)
        result.to_csv(args.output, index=False)
        print(f"[+] SLA assignments saved to: {args.output}")
        print(f"    Total: {len(result)}, Breached: {len(result[result['sla_status']=='breached'])}")

    elif args.command == "monitor":
        sla_df = pd.read_csv(args.sla_csv)
        monitor = SLAMonitor(sla_df)
        summary = monitor.get_compliance_summary()
        print(f"\n=== SLA Compliance Summary ===")
        print(f"Compliance Rate: {summary['compliance_rate']}")
        print(f"Breaches: {summary['breached']}")
        print(f"Avg MTTR: {summary['avg_mttr_days']} days")
        monitor.generate_report(args.report)

    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.2 KB
Keep exploring