Security Metrics and Reporting
Introduction
Security metrics translate technical security operations into business-relevant information that drives decision-making. Without metrics, security programs cannot demonstrate value, identify weaknesses, or justify resource allocation. Effective security reporting addresses multiple audiences — from technical teams to the board of directors — each with different information needs.
KPIs vs KRIs
Key Performance Indicators (KPIs)
KPIs measure the efficiency and effectiveness of security operations.
class SecurityKPI:
def __init__(self):
self.metrics = {}
def calculate_mttd(self, detection_times):
"""Mean Time to Detect — average time from compromise to detection."""
if not detection_times:
return None
return sum(detection_times) / len(detection_times)
def calculate_mttr(self, response_times):
"""Mean Time to Respond — average time from detection to containment."""
if not response_times:
return None
return sum(response_times) / len(response_times)
def calculate_coverage_rate(self, monitored_assets, total_assets):
"""Percentage of assets under monitoring."""
if total_assets == 0:
return 0
return (monitored_assets / total_assets) * 100
def calculate_patch_compliance(self, patched_systems, vulnerable_systems):
"""Percentage of systems patched within SLA."""
total = patched_systems + vulnerable_systems
if total == 0:
return 100
return (patched_systems / total) * 100
Key Risk Indicators (KRIs)
KRIs measure the level of security risk exposure.
class SecurityKRI:
def calculate_vulnerability_risk_score(self, vulnerabilities):
"""Weighted risk score based on CVSS and asset criticality."""
total_risk = 0
for vuln in vulnerabilities:
# CVSS score * asset criticality multiplier
risk = vuln['cvss'] * (vuln['asset_criticality'] / 5)
# Exploit availability multiplier
if vuln.get('exploit_available'):
risk *= 1.5
if vuln.get('in_wild'):
risk *= 2.0
total_risk += risk
return total_risk
def calculate_mean_time_to_patch(self, patch_times):
"""Average time to apply security patches by severity."""
categories = {'critical': [], 'high': [], 'medium': [], 'low': []}
for patch in patch_times:
categories[patch['severity']].append(patch['hours_to_patch'])
return {
severity: sum(times) / len(times) if times else 0
for severity, times in categories.items()
}
Dashboard Design
Effective dashboards present the right information at the right level of detail for the audience.
Executive Dashboard
def generate_executive_dashboard(metrics):
"""Board-level dashboard — strategic, summary, trend-focused."""
return {
'security_posture_score': metrics['posture_score'], # 0-100
'risk_trend': metrics['risk_trend'], # improving/stable/declining
'incidents_this_quarter': {
'total': metrics['incident_count'],
'critical': metrics['critical_incidents'],
'trend': metrics['incident_trend']
},
'top_risks': [
{'risk': 'Unpatched critical vulnerabilities',
'status': 'on_track', 'due_date': '2026-06-01'},
{'risk': 'Cloud misconfigurations',
'status': 'at_risk', 'due_date': '2026-05-15'},
],
'compliance_status': {
'soc2': 'compliant',
'pci_dss': 'compliant',
'hipaa': 'in_progress'
},
'budget_utilization': {
'allocated': 2500000,
'spent': 1850000,
'remaining': 650000
}
}
Operational Dashboard
def generate_operational_dashboard(soc_metrics):
"""SOC-level dashboard — tactical, detailed, real-time."""
return {
'alert_volume': {
'today': 847,
'change': '+12%',
'by_severity': {
'critical': 3,
'high': 27,
'medium': 145,
'low': 672
}
},
'mean_times': {
'mttd': '45 minutes',
'mttr': '3.2 hours',
'triage_time': '8 minutes'
},
'queue_status': {
'unassigned': 23,
'in_progress': 45,
'escalated': 12
},
'false_positive_rate': '28%',
'coverage': {
'endpoints': '98.5%',
'servers': '100%',
'cloud_accounts': '95%'
}
}
Board Reporting Framework
quarterly_board_report:
sections:
- title: "Executive Summary"
content:
- "Security posture improved from 72 to 78 (target: 80)"
- "Zero critical incidents this quarter"
- "Three compliance audits passed"
- title: "Incident Summary"
metrics:
- name: "Total Incidents"
value: 12
trend: "decreasing"
- name: "Mean Time to Detect"
value: "45 min"
target: "< 60 min"
status: "on_track"
- name: "Mean Time to Respond"
value: "3.2 hrs"
target: "< 4 hrs"
status: "on_track"
- name: "Phishing Click Rate"
value: "4.2%"
target: "< 5%"
status: "on_track"
- title: "Risk Profile"
risks:
- id: "R-001"
description: "Third-party vendor access to production"
likelihood: "medium"
impact: "high"
mitigation: "Vendor access review in progress"
target_date: "2026-07-01"
- title: "Compliance Status"
frameworks:
- name: "SOC 2 Type II"
status: "compliant"
last_audit: "2026-03-15"
- name: "PCI DSS 4.0"
status: "compliant"
last_audit: "2026-02-28"
- name: "ISO 27001"
status: "in_progress"
target: "2026-09-01"
- title: "Resource Allocation"
budget:
allocated: "$2.5M"
spent: "$1.85M (74%)"
key_investments:
- "EDR platform upgrade: $450K"
- "Security awareness training: $85K"
- "Penetration testing: $120K"
Security Scorecards
def generate_team_scorecard(metrics):
"""Department-level scorecard for security team performance."""
thresholds = {
'patch_compliance': {'good': 95, 'acceptable': 85},
'coverage': {'good': 98, 'acceptable': 90},
'false_positive_rate': {'good': 20, 'acceptable': 35},
'mttd_minutes': {'good': 30, 'acceptable': 60},
'mttr_hours': {'good': 2, 'acceptable': 4},
}
scorecard = {}
for metric, value in metrics.items():
if metric not in thresholds:
continue
threshold = thresholds[metric]
if value >= threshold['good']:
scorecard[metric] = 'GREEN'
elif value >= threshold['acceptable']:
scorecard[metric] = 'YELLOW'
else:
scorecard[metric] = 'RED'
return scorecard
Industry Benchmarks
industry_benchmarks:
mttd:
top_performer: "< 1 hour"
average: "24-48 hours"
below_average: "> 1 week"
mttr:
top_performer: "< 2 hours"
average: "4-8 hours"
below_average: "> 24 hours"
vulnerability_remediation:
critical: "15 days (top), 30 days (average)"
high: "30 days (top), 60 days (average)"
security_spend:
as_percentage_of_it: "5-10% (recommended)"
per_employee: "$1,500-2,500 (enterprise)"
Conclusion
Security metrics must be meaningful, measurable, and actionable. Distinguish between KPIs that measure operational effectiveness and KRIs that measure risk exposure. Tailor dashboards for each audience — executives need strategic trends and risk summaries, while SOC teams need real-time operational data. Benchmark against industry peers, track trends over time (not just snapshots), and always tie metrics back to business impact and risk reduction.