Skip to main content

Incident Response for Healthcare

When (not if) a security incident occurs, your response determines whether it becomes a manageable event or a catastrophic breach. HIPAA mandates specific breach notification requirements, but effective incident response goes far beyond compliance—it protects patients, preserves evidence, and minimizes business impact.
Learning Objectives:
  • Build a comprehensive incident response program
  • Detect and classify security incidents
  • Execute containment and eradication procedures
  • Meet HIPAA breach notification requirements
  • Conduct forensic investigations
  • Perform effective post-incident analysis
Estimated Time: 8-10 hours
Hands-On Labs: Tabletop exercise + Incident simulation
Prerequisites: HIPAA Fundamentals, Audit Logging

HIPAA Breach Notification Requirements

┌─────────────────────────────────────────────────────────────────────────────┐
│                    HIPAA BREACH NOTIFICATION RULE                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  45 CFR §§ 164.400-414 - BREACH NOTIFICATION REQUIREMENTS                  │
│  ────────────────────────────────────────────────────────                   │
│                                                                              │
│  WHAT IS A BREACH?                                                          │
│  ─────────────────                                                          │
│  "Acquisition, access, use, or disclosure of PHI in a manner not           │
│   permitted under the Privacy Rule which compromises the security           │
│   or privacy of the PHI."                                                   │
│                                                                              │
│  NOTIFICATION TIMELINES:                                                    │
│  ───────────────────────                                                    │
│                                                                              │
│  ┌──────────────────────┬───────────────────────────────────────────────┐  │
│  │ Affected Parties     │ Timeline                                      │  │
│  ├──────────────────────┼───────────────────────────────────────────────┤  │
│  │ Individuals          │ Within 60 days of discovery                   │  │
│  │ HHS (≥500 people)    │ Within 60 days of discovery                   │  │
│  │ HHS (<500 people)    │ Within 60 days of calendar year end           │  │
│  │ Media (≥500 in state)│ Within 60 days of discovery                   │  │
│  │ Business Associate   │ Notify Covered Entity without unreasonable    │  │
│  │                      │ delay, no later than 60 days                  │  │
│  └──────────────────────┴───────────────────────────────────────────────┘  │
│                                                                              │
│  EXCEPTION: Encrypted Data                                                  │
│  ─────────────────────────                                                  │
│  If data was encrypted per NIST standards and the key was not              │
│  compromised, it is NOT considered a breach (safe harbor).                 │
│                                                                              │
│  PENALTY TIERS (per violation category per year):                          │
│  ─────────────────────────────────────────────────                          │
│  • Tier 1 (Unknowing): $100 - $50,000 (max $1.5M)                          │
│  • Tier 2 (Reasonable Cause): $1,000 - $50,000 (max $1.5M)                 │
│  • Tier 3 (Willful Neglect - Corrected): $10,000 - $50,000 (max $1.5M)     │
│  • Tier 4 (Willful Neglect - Not Corrected): $50,000 (max $1.5M)           │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Incident Response Program Structure

The NIST Incident Response Lifecycle

┌─────────────────────────────────────────────────────────────────────────────┐
│                    INCIDENT RESPONSE LIFECYCLE                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                      1. PREPARATION                                  │   │
│   │   • Policies & procedures    • Training                             │   │
│   │   • Incident response team   • Tools & resources                    │   │
│   │   • Communication plans      • Tabletop exercises                   │   │
│   └───────────────────────────────────┬─────────────────────────────────┘   │
│                                       │                                      │
│                                       ▼                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                  2. DETECTION & ANALYSIS                             │   │
│   │   • Monitoring & alerting    • Initial triage                       │   │
│   │   • Incident classification  • Scope determination                  │   │
│   │   • Evidence preservation    • Escalation                           │   │
│   └───────────────────────────────────┬─────────────────────────────────┘   │
│                                       │                                      │
│                                       ▼                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │               3. CONTAINMENT, ERADICATION, RECOVERY                  │   │
│   │   • Short-term containment   • Evidence collection                  │   │
│   │   • System isolation         • Malware removal                      │   │
│   │   • Patch vulnerabilities    • System restoration                   │   │
│   │   • Verify clean state       • Return to operations                 │   │
│   └───────────────────────────────────┬─────────────────────────────────┘   │
│                                       │                                      │
│                                       ▼                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                   4. POST-INCIDENT ACTIVITY                          │   │
│   │   • Breach determination     • Breach notification                  │   │
│   │   • Lessons learned          • Control improvements                 │   │
│   │   • Documentation update     • Metrics & reporting                  │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Phase 1: Preparation

Incident Response Team Structure

from dataclasses import dataclass, field
from typing import List, Dict, Optional
from enum import Enum
from datetime import datetime

class IRTeamRole(Enum):
    """Incident Response Team Roles"""
    IR_LEAD = "ir_lead"
    SECURITY_ANALYST = "security_analyst"
    FORENSICS_SPECIALIST = "forensics_specialist"
    LEGAL_COUNSEL = "legal_counsel"
    PRIVACY_OFFICER = "privacy_officer"
    COMMUNICATIONS = "communications"
    IT_OPERATIONS = "it_operations"
    EXECUTIVE_SPONSOR = "executive_sponsor"
    CLINICAL_LIAISON = "clinical_liaison"
    HR_REPRESENTATIVE = "hr_representative"

@dataclass
class IRTeamMember:
    """Incident Response Team Member"""
    name: str
    role: IRTeamRole
    primary_phone: str
    secondary_phone: str
    email: str
    backup_person: Optional[str] = None
    availability: str = "24/7"  # or specific hours
    
@dataclass
class IncidentResponseTeam:
    """
    Incident Response Team Configuration
    
    HIPAA requires designated security incident procedures (§164.308(a)(6))
    """
    
    team_name: str = "Healthcare Security Incident Response Team (HSIRT)"
    
    members: List[IRTeamMember] = field(default_factory=list)
    
    # Escalation thresholds
    escalation_levels: Dict[str, List[IRTeamRole]] = field(default_factory=lambda: {
        "low": [IRTeamRole.SECURITY_ANALYST],
        "medium": [IRTeamRole.SECURITY_ANALYST, IRTeamRole.IR_LEAD],
        "high": [
            IRTeamRole.IR_LEAD, 
            IRTeamRole.PRIVACY_OFFICER, 
            IRTeamRole.LEGAL_COUNSEL
        ],
        "critical": [
            IRTeamRole.IR_LEAD,
            IRTeamRole.PRIVACY_OFFICER,
            IRTeamRole.LEGAL_COUNSEL,
            IRTeamRole.EXECUTIVE_SPONSOR,
            IRTeamRole.COMMUNICATIONS,
        ],
    })
    
    # Communication channels
    primary_channel: str = "Secure Slack #incident-response"
    bridge_line: str = "+1-XXX-XXX-XXXX"
    war_room_location: str = "Conference Room B, Building 1"
    
    def get_on_call(self, role: IRTeamRole) -> Optional[IRTeamMember]:
        """Get current on-call person for role"""
        for member in self.members:
            if member.role == role:
                return member
        return None
    
    def activate_team(self, severity: str) -> List[IRTeamMember]:
        """Activate team members based on severity"""
        roles_needed = self.escalation_levels.get(severity, [])
        return [
            member for member in self.members 
            if member.role in roles_needed
        ]


# Example team configuration
ir_team = IncidentResponseTeam(
    members=[
        IRTeamMember(
            name="Sarah Chen",
            role=IRTeamRole.IR_LEAD,
            primary_phone="+1-555-0100",
            secondary_phone="+1-555-0101",
            email="[email protected]",
            backup_person="Mike Rodriguez",
        ),
        IRTeamMember(
            name="James Williams",
            role=IRTeamRole.SECURITY_ANALYST,
            primary_phone="+1-555-0102",
            secondary_phone="+1-555-0103",
            email="[email protected]",
        ),
        IRTeamMember(
            name="Dr. Emily Foster",
            role=IRTeamRole.PRIVACY_OFFICER,
            primary_phone="+1-555-0104",
            secondary_phone="+1-555-0105",
            email="[email protected]",
        ),
        IRTeamMember(
            name="Robert Kim",
            role=IRTeamRole.LEGAL_COUNSEL,
            primary_phone="+1-555-0106",
            secondary_phone="+1-555-0107",
            email="[email protected]",
        ),
    ]
)

Incident Classification

from enum import Enum
from dataclasses import dataclass
from typing import List, Optional

class IncidentCategory(Enum):
    """Categories of security incidents"""
    MALWARE = "malware"
    RANSOMWARE = "ransomware"
    UNAUTHORIZED_ACCESS = "unauthorized_access"
    DATA_EXFILTRATION = "data_exfiltration"
    INSIDER_THREAT = "insider_threat"
    PHISHING = "phishing"
    DENIAL_OF_SERVICE = "denial_of_service"
    LOST_DEVICE = "lost_device"
    IMPROPER_DISCLOSURE = "improper_disclosure"
    SYSTEM_COMPROMISE = "system_compromise"
    PHYSICAL_BREACH = "physical_breach"
    VENDOR_BREACH = "vendor_breach"

class IncidentSeverity(Enum):
    """Severity levels for incidents"""
    CRITICAL = "critical"   # Immediate threat to patient safety or massive PHI exposure
    HIGH = "high"           # Significant PHI exposure or system compromise
    MEDIUM = "medium"       # Limited PHI exposure or potential for escalation
    LOW = "low"             # Minor incident, no PHI exposure confirmed

@dataclass
class IncidentClassification:
    """
    Incident classification framework
    
    Used to determine response priority and resource allocation
    """
    
    # Classification criteria
    phi_involved: bool = False
    phi_volume: str = "none"  # none, single, limited (<500), large (≥500)
    patient_safety_impact: bool = False
    systems_affected: List[str] = None
    ongoing_threat: bool = False
    public_exposure: bool = False
    
    @property
    def severity(self) -> IncidentSeverity:
        """Calculate severity based on criteria"""
        
        # Critical conditions
        if self.patient_safety_impact:
            return IncidentSeverity.CRITICAL
        if self.phi_volume == "large" and self.public_exposure:
            return IncidentSeverity.CRITICAL
        if self.ongoing_threat and self.phi_involved:
            return IncidentSeverity.CRITICAL
        
        # High conditions
        if self.phi_volume == "large":
            return IncidentSeverity.HIGH
        if self.public_exposure and self.phi_involved:
            return IncidentSeverity.HIGH
        if len(self.systems_affected or []) > 5:
            return IncidentSeverity.HIGH
        
        # Medium conditions
        if self.phi_volume in ["single", "limited"]:
            return IncidentSeverity.MEDIUM
        if self.phi_involved:
            return IncidentSeverity.MEDIUM
        
        return IncidentSeverity.LOW
    
    @property
    def response_sla(self) -> dict:
        """Get response SLA based on severity"""
        slas = {
            IncidentSeverity.CRITICAL: {
                "initial_response": "15 minutes",
                "containment": "1 hour",
                "executive_notification": "30 minutes",
                "status_updates": "every 30 minutes",
            },
            IncidentSeverity.HIGH: {
                "initial_response": "30 minutes",
                "containment": "4 hours",
                "executive_notification": "2 hours",
                "status_updates": "every 2 hours",
            },
            IncidentSeverity.MEDIUM: {
                "initial_response": "2 hours",
                "containment": "24 hours",
                "executive_notification": "next business day",
                "status_updates": "daily",
            },
            IncidentSeverity.LOW: {
                "initial_response": "next business day",
                "containment": "1 week",
                "executive_notification": "as needed",
                "status_updates": "weekly",
            },
        }
        return slas[self.severity]

Phase 2: Detection & Analysis

Incident Detection Sources

from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Optional, Dict, Any
from enum import Enum
import uuid

class DetectionSource(Enum):
    """Sources of incident detection"""
    SIEM = "siem"
    EDR = "edr"
    IDS_IPS = "ids_ips"
    ANTIVIRUS = "antivirus"
    USER_REPORT = "user_report"
    AUDIT_LOG = "audit_log"
    THREAT_INTEL = "threat_intel"
    VENDOR_NOTIFICATION = "vendor_notification"
    LAW_ENFORCEMENT = "law_enforcement"
    MEDIA = "media"
    DARK_WEB_MONITORING = "dark_web_monitoring"
    VULNERABILITY_SCAN = "vulnerability_scan"

@dataclass
class SecurityAlert:
    """Initial security alert triggering investigation"""
    
    alert_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    
    # Source information
    source: DetectionSource = DetectionSource.SIEM
    source_system: str = ""
    source_rule: str = ""
    
    # Alert details
    title: str = ""
    description: str = ""
    raw_data: Dict[str, Any] = field(default_factory=dict)
    
    # Timing
    detected_at: datetime = field(default_factory=datetime.utcnow)
    event_time: Optional[datetime] = None
    
    # Affected systems
    affected_hosts: List[str] = field(default_factory=list)
    affected_users: List[str] = field(default_factory=list)
    affected_data: List[str] = field(default_factory=list)
    
    # Initial assessment
    initial_severity: str = "unknown"
    phi_suspected: bool = False
    
    # Status
    status: str = "new"  # new, investigating, escalated, closed
    assigned_to: Optional[str] = None


@dataclass
class Incident:
    """
    Security incident record
    
    Created when alert is confirmed as genuine incident
    """
    
    incident_id: str = field(default_factory=lambda: f"INC-{datetime.utcnow().strftime('%Y%m%d')}-{str(uuid.uuid4())[:8].upper()}")
    
    # Classification
    category: IncidentCategory = IncidentCategory.UNAUTHORIZED_ACCESS
    classification: Optional[IncidentClassification] = None
    
    # Timeline
    detected_at: datetime = field(default_factory=datetime.utcnow)
    reported_at: Optional[datetime] = None
    contained_at: Optional[datetime] = None
    eradicated_at: Optional[datetime] = None
    recovered_at: Optional[datetime] = None
    closed_at: Optional[datetime] = None
    
    # Source
    triggered_by_alerts: List[str] = field(default_factory=list)
    detection_source: DetectionSource = DetectionSource.SIEM
    
    # Description
    title: str = ""
    executive_summary: str = ""
    technical_details: str = ""
    
    # Impact
    affected_systems: List[str] = field(default_factory=list)
    affected_users: List[str] = field(default_factory=list)
    affected_patients: List[str] = field(default_factory=list)  # For breach assessment
    phi_types_exposed: List[str] = field(default_factory=list)
    
    # Response
    status: str = "open"
    current_phase: str = "detection"
    assigned_team: List[str] = field(default_factory=list)
    ir_lead: Optional[str] = None
    
    # Breach assessment
    is_breach: Optional[bool] = None
    breach_determination_date: Optional[datetime] = None
    breach_notification_required: bool = False
    notification_deadline: Optional[datetime] = None
    
    # Evidence
    evidence_collected: List[str] = field(default_factory=list)
    forensic_images: List[str] = field(default_factory=list)
    
    # Actions taken
    actions: List[Dict] = field(default_factory=list)
    
    def add_action(self, action_type: str, description: str, performed_by: str):
        """Log an action taken during incident response"""
        self.actions.append({
            "timestamp": datetime.utcnow().isoformat(),
            "action_type": action_type,
            "description": description,
            "performed_by": performed_by,
        })
    
    def calculate_notification_deadline(self):
        """Calculate breach notification deadline (60 days from discovery)"""
        from datetime import timedelta
        if self.breach_notification_required:
            self.notification_deadline = self.detected_at + timedelta(days=60)


class IncidentManager:
    """Incident lifecycle management"""
    
    def __init__(self):
        self.incidents: Dict[str, Incident] = {}
        self.alerts: Dict[str, SecurityAlert] = {}
    
    def create_incident_from_alert(
        self,
        alert: SecurityAlert,
        classification: IncidentClassification,
        title: str,
        created_by: str,
    ) -> Incident:
        """Create incident from confirmed alert"""
        
        incident = Incident(
            category=self._infer_category(alert),
            classification=classification,
            detected_at=alert.detected_at,
            reported_at=datetime.utcnow(),
            triggered_by_alerts=[alert.alert_id],
            detection_source=alert.source,
            title=title,
            affected_systems=alert.affected_hosts,
            affected_users=alert.affected_users,
        )
        
        incident.add_action(
            "incident_created",
            f"Incident created from alert {alert.alert_id}",
            created_by,
        )
        
        # Update alert status
        alert.status = "escalated"
        
        self.incidents[incident.incident_id] = incident
        
        # Trigger notifications based on severity
        self._trigger_notifications(incident)
        
        return incident
    
    def update_incident_phase(
        self,
        incident_id: str,
        new_phase: str,
        updated_by: str,
        notes: str = "",
    ):
        """Update incident phase"""
        incident = self.incidents.get(incident_id)
        if not incident:
            return
        
        old_phase = incident.current_phase
        incident.current_phase = new_phase
        
        # Set phase timestamps
        if new_phase == "containment":
            incident.contained_at = datetime.utcnow()
        elif new_phase == "eradication":
            incident.eradicated_at = datetime.utcnow()
        elif new_phase == "recovery":
            incident.recovered_at = datetime.utcnow()
        elif new_phase == "closed":
            incident.closed_at = datetime.utcnow()
            incident.status = "closed"
        
        incident.add_action(
            "phase_change",
            f"Phase changed from {old_phase} to {new_phase}. {notes}",
            updated_by,
        )
    
    def _infer_category(self, alert: SecurityAlert) -> IncidentCategory:
        """Infer incident category from alert"""
        title_lower = alert.title.lower()
        
        if "ransomware" in title_lower:
            return IncidentCategory.RANSOMWARE
        if "malware" in title_lower:
            return IncidentCategory.MALWARE
        if "phishing" in title_lower:
            return IncidentCategory.PHISHING
        if "exfil" in title_lower:
            return IncidentCategory.DATA_EXFILTRATION
        if "insider" in title_lower:
            return IncidentCategory.INSIDER_THREAT
        
        return IncidentCategory.UNAUTHORIZED_ACCESS
    
    def _trigger_notifications(self, incident: Incident):
        """Trigger notifications based on severity"""
        severity = incident.classification.severity if incident.classification else IncidentSeverity.MEDIUM
        
        notification = {
            "incident_id": incident.incident_id,
            "severity": severity.value,
            "title": incident.title,
            "phi_involved": incident.classification.phi_involved if incident.classification else False,
            "timestamp": datetime.utcnow().isoformat(),
        }
        
        # In production: Send to appropriate channels
        print(f"NOTIFICATION: {notification}")

Phase 3: Containment, Eradication, Recovery

Containment Playbooks

from dataclasses import dataclass
from typing import List, Callable
from enum import Enum

@dataclass
class PlaybookStep:
    """Single step in incident response playbook"""
    step_number: int
    title: str
    description: str
    responsible_role: str
    estimated_time: str
    verification: str  # How to verify step completion
    automated: bool = False
    automation_script: str = ""

@dataclass
class IncidentPlaybook:
    """
    Incident response playbook
    
    Pre-defined response procedures for common incident types
    """
    
    playbook_id: str
    name: str
    incident_category: IncidentCategory
    description: str
    
    # Steps
    containment_steps: List[PlaybookStep]
    eradication_steps: List[PlaybookStep]
    recovery_steps: List[PlaybookStep]
    
    # Requirements
    required_tools: List[str]
    required_access: List[str]
    
    # Approvals
    requires_executive_approval: bool = False
    requires_legal_approval: bool = False


# Ransomware Playbook
RANSOMWARE_PLAYBOOK = IncidentPlaybook(
    playbook_id="PB-001",
    name="Ransomware Response",
    incident_category=IncidentCategory.RANSOMWARE,
    description="Response procedures for ransomware infections",
    
    containment_steps=[
        PlaybookStep(
            step_number=1,
            title="Isolate Infected Systems",
            description="""
            IMMEDIATELY disconnect infected systems from network:
            1. Disable network ports at switch level
            2. Disable Wi-Fi adapters
            3. Do NOT power off systems (preserves memory evidence)
            4. Block IP addresses at firewall
            """,
            responsible_role="IT Operations",
            estimated_time="15 minutes",
            verification="Ping test to isolated systems fails",
        ),
        PlaybookStep(
            step_number=2,
            title="Block Lateral Movement",
            description="""
            Prevent spread to other systems:
            1. Block SMB (ports 445, 139) internally
            2. Disable RDP between systems
            3. Block PowerShell remoting
            4. Isolate network segments if needed
            """,
            responsible_role="Network Security",
            estimated_time="30 minutes",
            verification="Network scans show blocked ports",
        ),
        PlaybookStep(
            step_number=3,
            title="Preserve Evidence",
            description="""
            Capture volatile data before any changes:
            1. Memory dumps of infected systems
            2. Network traffic captures
            3. Ransom notes and encrypted file samples
            4. Screenshot of ransom demands
            """,
            responsible_role="Forensics",
            estimated_time="1-2 hours",
            verification="Evidence chain of custody documented",
        ),
        PlaybookStep(
            step_number=4,
            title="Assess Scope",
            description="""
            Determine extent of infection:
            1. Query EDR for IoCs across all endpoints
            2. Check file shares for encrypted files
            3. Review backup system status
            4. Identify PHI systems affected
            """,
            responsible_role="Security Analyst",
            estimated_time="2-4 hours",
            verification="Scope document completed",
        ),
    ],
    
    eradication_steps=[
        PlaybookStep(
            step_number=1,
            title="Identify Ransomware Variant",
            description="""
            Determine specific ransomware family:
            1. Check ID Ransomware (id-ransomware.malwarehunterteam.com)
            2. Analyze ransom note format
            3. Check for decryptor availability
            4. Report to FBI IC3 if in US
            """,
            responsible_role="Security Analyst",
            estimated_time="1 hour",
            verification="Ransomware variant identified",
        ),
        PlaybookStep(
            step_number=2,
            title="Clean Infected Systems",
            description="""
            Remove ransomware:
            1. For non-critical: Wipe and reimage
            2. For critical: Full forensic cleaning if possible
            3. Remove persistence mechanisms
            4. Reset all credentials accessed from infected systems
            """,
            responsible_role="IT Operations",
            estimated_time="4-8 hours per system",
            verification="EDR confirms no IoCs present",
        ),
        PlaybookStep(
            step_number=3,
            title="Close Entry Vector",
            description="""
            Eliminate how attacker got in:
            1. Patch exploited vulnerabilities
            2. Block phishing email IOCs
            3. Update email filters
            4. Strengthen authentication (add MFA)
            """,
            responsible_role="Security Engineering",
            estimated_time="2-4 hours",
            verification="Entry vector documented and closed",
        ),
    ],
    
    recovery_steps=[
        PlaybookStep(
            step_number=1,
            title="Validate Backups",
            description="""
            Ensure backups are clean and complete:
            1. Scan backup media for ransomware
            2. Verify backup integrity
            3. Test restore procedures
            4. Determine recovery point (last clean backup)
            """,
            responsible_role="IT Operations",
            estimated_time="2-4 hours",
            verification="Backup validation report",
        ),
        PlaybookStep(
            step_number=2,
            title="Restore Systems",
            description="""
            Begin phased restoration:
            1. Prioritize critical clinical systems
            2. Restore from verified clean backups
            3. Validate application functionality
            4. Monitor for reinfection
            """,
            responsible_role="IT Operations",
            estimated_time="Variable (hours to days)",
            verification="Systems operational and monitored",
        ),
        PlaybookStep(
            step_number=3,
            title="Return to Normal Operations",
            description="""
            Safely resume operations:
            1. Reconnect systems to network gradually
            2. Enhanced monitoring for 30 days
            3. User password resets
            4. Document incident lessons learned
            """,
            responsible_role="IT Operations",
            estimated_time="1-2 weeks",
            verification="All systems operational, monitoring in place",
        ),
    ],
    
    required_tools=[
        "EDR console access",
        "Network monitoring tools",
        "Memory forensics toolkit",
        "Backup/restore system access",
        "Firewall management access",
    ],
    
    required_access=[
        "Domain admin credentials (break-glass)",
        "Network infrastructure access",
        "Backup system access",
        "Cloud console access",
    ],
    
    requires_executive_approval=True,  # For ransom payment decisions
    requires_legal_approval=True,  # For breach notification
)


# Data Exfiltration Playbook
DATA_EXFILTRATION_PLAYBOOK = IncidentPlaybook(
    playbook_id="PB-002",
    name="Data Exfiltration Response",
    incident_category=IncidentCategory.DATA_EXFILTRATION,
    description="Response procedures for confirmed or suspected data theft",
    
    containment_steps=[
        PlaybookStep(
            step_number=1,
            title="Block Active Exfiltration",
            description="""
            Stop ongoing data theft:
            1. Block destination IP addresses at firewall
            2. Disable suspect user accounts
            3. Block USB/external media
            4. Terminate suspicious processes
            """,
            responsible_role="Security Operations",
            estimated_time="15 minutes",
            verification="No active outbound connections to destinations",
        ),
        PlaybookStep(
            step_number=2,
            title="Preserve Evidence",
            description="""
            Capture all relevant evidence:
            1. Network traffic captures (PCAP)
            2. Proxy/firewall logs
            3. DLP alerts
            4. User activity logs
            5. Email logs if email was exfil method
            """,
            responsible_role="Forensics",
            estimated_time="2 hours",
            verification="Evidence preserved and documented",
        ),
        PlaybookStep(
            step_number=3,
            title="Assess Data Involved",
            description="""
            Determine what data was exfiltrated:
            1. Review DLP logs for data classification
            2. Analyze file access logs
            3. Identify affected databases/file shares
            4. Determine if PHI involved
            5. Count affected patient records if PHI
            """,
            responsible_role="Security Analyst",
            estimated_time="4-8 hours",
            verification="Data assessment report completed",
        ),
    ],
    
    eradication_steps=[
        PlaybookStep(
            step_number=1,
            title="Close Access Vector",
            description="""
            Eliminate attacker access:
            1. Revoke all access for compromised accounts
            2. Reset credentials
            3. Revoke API keys/tokens
            4. Review and revoke third-party access
            """,
            responsible_role="IT Security",
            estimated_time="2-4 hours",
            verification="All compromised access revoked",
        ),
        PlaybookStep(
            step_number=2,
            title="Sweep for Persistence",
            description="""
            Check for ongoing access:
            1. Hunt for backdoors
            2. Review authorized SSH keys
            3. Check for rogue admin accounts
            4. Verify cloud IAM permissions
            """,
            responsible_role="Security Operations",
            estimated_time="4-8 hours",
            verification="No unauthorized access mechanisms found",
        ),
    ],
    
    recovery_steps=[
        PlaybookStep(
            step_number=1,
            title="Implement Enhanced Monitoring",
            description="""
            Increase detection capability:
            1. Enhance DLP rules
            2. Add network monitoring for affected data types
            3. Implement user behavior analytics
            4. Increase log retention
            """,
            responsible_role="Security Engineering",
            estimated_time="1-2 days",
            verification="Enhanced monitoring operational",
        ),
        PlaybookStep(
            step_number=2,
            title="Breach Notification (if required)",
            description="""
            Execute notification requirements:
            1. Complete breach risk assessment
            2. Prepare notification letters
            3. Notify affected individuals within 60 days
            4. Notify HHS if ≥500 individuals
            5. Notify media if ≥500 in a state
            """,
            responsible_role="Privacy Officer",
            estimated_time="Variable",
            verification="All notifications sent and documented",
        ),
    ],
    
    required_tools=[
        "DLP console",
        "Network monitoring (PCAP capability)",
        "SIEM/log analysis",
        "Identity management system",
    ],
    
    required_access=[
        "DLP admin",
        "Network infrastructure",
        "Identity management admin",
        "Log management system",
    ],
    
    requires_executive_approval=False,
    requires_legal_approval=True,  # For breach notification
)

Phase 4: Breach Determination & Notification

HIPAA Breach Risk Assessment

from dataclasses import dataclass
from typing import List, Optional
from enum import Enum
from datetime import datetime

class RiskFactor(Enum):
    """HIPAA breach risk assessment factors"""
    NATURE_AND_EXTENT = "nature_and_extent"
    UNAUTHORIZED_PERSON = "unauthorized_person"
    PHI_ACQUIRED_VIEWED = "phi_acquired_viewed"
    RISK_MITIGATION = "risk_mitigation"

@dataclass
class BreachRiskAssessment:
    """
    HIPAA Breach Risk Assessment
    
    Per 45 CFR 164.402, breach assessment must consider:
    1. Nature and extent of PHI involved
    2. Unauthorized person who used PHI or to whom it was disclosed
    3. Whether PHI was actually acquired or viewed
    4. Extent to which risk has been mitigated
    """
    
    incident_id: str
    assessment_date: datetime = None
    assessor: str = ""
    
    # Factor 1: Nature and extent of PHI
    phi_types: List[str] = None  # SSN, diagnosis, treatment, financial
    phi_sensitivity: str = ""  # low, medium, high (mental health, HIV, substance abuse = high)
    number_of_individuals: int = 0
    
    # Factor 2: Unauthorized person
    unauthorized_person_identified: bool = False
    unauthorized_person_type: str = ""  # employee, external, unknown
    likelihood_of_reidentification: str = ""  # low, medium, high
    
    # Factor 3: PHI acquired or viewed
    phi_actually_acquired: bool = False
    phi_actually_viewed: bool = False
    evidence_of_access: str = ""
    
    # Factor 4: Mitigation
    mitigation_steps: List[str] = None
    mitigation_effectiveness: str = ""  # none, partial, full
    
    # Encryption status (safe harbor)
    data_was_encrypted: bool = False
    encryption_meets_nist: bool = False
    encryption_key_compromised: bool = False
    
    # Assessment outcome
    breach_determination: Optional[bool] = None
    determination_rationale: str = ""
    
    @property
    def qualifies_for_safe_harbor(self) -> bool:
        """Check if encryption safe harbor applies"""
        return (
            self.data_was_encrypted and 
            self.encryption_meets_nist and 
            not self.encryption_key_compromised
        )
    
    def calculate_risk_score(self) -> dict:
        """Calculate risk score for each factor"""
        scores = {
            "nature_extent": 0,
            "unauthorized_person": 0,
            "phi_accessed": 0,
            "mitigation": 0,
        }
        
        # Factor 1: Nature and extent
        if "ssn" in (self.phi_types or []):
            scores["nature_extent"] += 3
        if "financial" in (self.phi_types or []):
            scores["nature_extent"] += 3
        if self.phi_sensitivity == "high":
            scores["nature_extent"] += 3
        if self.number_of_individuals > 500:
            scores["nature_extent"] += 2
        elif self.number_of_individuals > 100:
            scores["nature_extent"] += 1
        
        # Factor 2: Unauthorized person
        if self.unauthorized_person_type == "external":
            scores["unauthorized_person"] += 3
        elif self.unauthorized_person_type == "employee":
            scores["unauthorized_person"] += 2
        if self.likelihood_of_reidentification == "high":
            scores["unauthorized_person"] += 2
        
        # Factor 3: PHI accessed
        if self.phi_actually_acquired:
            scores["phi_accessed"] += 3
        elif self.phi_actually_viewed:
            scores["phi_accessed"] += 2
        elif not self.phi_actually_acquired and not self.phi_actually_viewed:
            scores["phi_accessed"] += 0  # Reduces overall risk
        
        # Factor 4: Mitigation (reduces risk)
        if self.mitigation_effectiveness == "full":
            scores["mitigation"] -= 3
        elif self.mitigation_effectiveness == "partial":
            scores["mitigation"] -= 1
        
        return scores
    
    def determine_breach(self) -> tuple[bool, str]:
        """
        Determine if incident constitutes a breach
        
        Returns:
            Tuple of (is_breach: bool, rationale: str)
        """
        # Check safe harbor first
        if self.qualifies_for_safe_harbor:
            return False, "Encryption safe harbor applies - data was encrypted per NIST standards and key was not compromised"
        
        # Calculate risk
        scores = self.calculate_risk_score()
        total_score = sum(scores.values())
        
        # Low probability of compromise = not a breach
        if total_score <= 2:
            return False, f"Low probability of compromise (risk score: {total_score}). No notification required."
        
        # High probability = breach
        if total_score >= 6:
            return True, f"High probability of compromise (risk score: {total_score}). Breach notification required."
        
        # Medium - document carefully
        return True, f"Moderate probability of compromise (risk score: {total_score}). Recommend treating as breach."


@dataclass
class BreachNotification:
    """
    HIPAA Breach Notification Record
    """
    
    incident_id: str
    
    # What
    breach_description: str = ""
    phi_types_involved: List[str] = None
    
    # When
    discovery_date: datetime = None
    notification_deadline: datetime = None  # 60 days from discovery
    
    # Who
    number_affected: int = 0
    
    # Notifications sent
    individual_notifications: List[dict] = None
    hhs_notification_date: Optional[datetime] = None
    media_notification_date: Optional[datetime] = None
    
    # Required content (per 45 CFR 164.404)
    notification_content: dict = None
    
    def generate_notification_content(self) -> dict:
        """Generate required notification content"""
        return {
            "brief_description": self.breach_description,
            "phi_types": self.phi_types_involved,
            "steps_for_individuals": [
                "Monitor credit reports and statements",
                "Consider placing fraud alerts",
                "Report suspicious activity",
            ],
            "what_we_are_doing": [
                "Investigating the incident",
                "Implementing additional safeguards",
                "Offering credit monitoring services",
            ],
            "contact_information": {
                "phone": "1-800-XXX-XXXX",
                "email": "[email protected]",
                "mail": "Privacy Officer, Organization Address",
            },
        }
    
    def generate_individual_letter(self, patient_name: str, patient_address: str) -> str:
        """Generate breach notification letter for individual"""
        content = self.generate_notification_content()
        
        letter = f"""
[ORGANIZATION LETTERHEAD]

{datetime.now().strftime("%B %d, %Y")}

{patient_name}
{patient_address}

RE: Notice of Data Breach

Dear {patient_name},

We are writing to inform you of an incident that may have affected the privacy of your 
protected health information (PHI).

WHAT HAPPENED
{content['brief_description']}

WHAT INFORMATION WAS INVOLVED
The following types of information may have been affected:
{', '.join(content['phi_types'])}

WHAT WE ARE DOING
{chr(10).join('• ' + step for step in content['what_we_are_doing'])}

WHAT YOU CAN DO
We recommend you take the following steps:
{chr(10).join('• ' + step for step in content['steps_for_individuals'])}

FOR MORE INFORMATION
If you have questions, please contact us:
Phone: {content['contact_information']['phone']}
Email: {content['contact_information']['email']}
Mail: {content['contact_information']['mail']}

We sincerely apologize for any inconvenience this may cause.

Sincerely,

[Privacy Officer Name]
Privacy Officer
        """
        return letter

Post-Incident Analysis

Lessons Learned Template

from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Dict

@dataclass
class LessonsLearned:
    """
    Post-incident lessons learned documentation
    
    HIPAA requires evaluation and updates based on incidents (§164.308(a)(8))
    """
    
    incident_id: str
    review_date: datetime = field(default_factory=datetime.utcnow)
    participants: List[str] = field(default_factory=list)
    
    # Timeline reconstruction
    timeline: List[Dict] = field(default_factory=list)
    
    # What worked well
    what_worked: List[str] = field(default_factory=list)
    
    # What didn't work
    what_didnt_work: List[str] = field(default_factory=list)
    
    # Root cause analysis
    root_causes: List[str] = field(default_factory=list)
    contributing_factors: List[str] = field(default_factory=list)
    
    # Improvement actions
    improvement_actions: List[Dict] = field(default_factory=list)
    
    # Metrics
    time_to_detect: str = ""
    time_to_contain: str = ""
    time_to_eradicate: str = ""
    time_to_recover: str = ""
    total_downtime: str = ""
    estimated_cost: float = 0.0
    
    def add_improvement_action(
        self,
        action: str,
        owner: str,
        due_date: str,
        priority: str = "medium",
    ):
        """Add improvement action with tracking"""
        self.improvement_actions.append({
            "action": action,
            "owner": owner,
            "due_date": due_date,
            "priority": priority,
            "status": "open",
            "created_at": datetime.utcnow().isoformat(),
        })
    
    def generate_report(self) -> str:
        """Generate lessons learned report"""
        report = f"""
# Incident Post-Mortem Report

## Incident: {self.incident_id}
**Review Date:** {self.review_date.strftime("%Y-%m-%d")}
**Participants:** {", ".join(self.participants)}

---

## Timeline
| Time | Event |
|------|-------|
"""
        for event in self.timeline:
            report += f"| {event['time']} | {event['event']} |\n"
        
        report += f"""
---

## Response Metrics
- **Time to Detect:** {self.time_to_detect}
- **Time to Contain:** {self.time_to_contain}
- **Time to Eradicate:** {self.time_to_eradicate}
- **Time to Recover:** {self.time_to_recover}
- **Total Downtime:** {self.total_downtime}
- **Estimated Cost:** ${self.estimated_cost:,.2f}

---

## What Worked Well
"""
        for item in self.what_worked:
            report += f"- {item}\n"
        
        report += "\n## What Didn't Work Well\n"
        for item in self.what_didnt_work:
            report += f"- {item}\n"
        
        report += "\n## Root Causes\n"
        for cause in self.root_causes:
            report += f"- {cause}\n"
        
        report += "\n## Improvement Actions\n"
        report += "| Action | Owner | Due Date | Priority | Status |\n"
        report += "|--------|-------|----------|----------|--------|\n"
        for action in self.improvement_actions:
            report += f"| {action['action']} | {action['owner']} | {action['due_date']} | {action['priority']} | {action['status']} |\n"
        
        return report


# Example lessons learned
lessons = LessonsLearned(
    incident_id="INC-20240115-A1B2C3D4",
    participants=["IR Lead", "Security Analyst", "Privacy Officer", "IT Director"],
)

lessons.timeline = [
    {"time": "2024-01-15 14:30", "event": "SIEM alert triggered for unusual file access"},
    {"time": "2024-01-15 14:45", "event": "Security analyst began investigation"},
    {"time": "2024-01-15 15:00", "event": "Incident confirmed, IR Lead notified"},
    {"time": "2024-01-15 15:30", "event": "Affected account disabled"},
    {"time": "2024-01-15 16:00", "event": "Scope assessment completed"},
    {"time": "2024-01-16 10:00", "event": "Forensic analysis completed"},
    {"time": "2024-01-17 14:00", "event": "Recovery completed"},
]

lessons.what_worked = [
    "SIEM alerting detected anomaly within 30 minutes",
    "IR team responded within SLA",
    "Audit logs were complete and available",
    "Backup restoration was successful",
]

lessons.what_didnt_work = [
    "Initial triage took too long (45 minutes)",
    "Communication with executives was delayed",
    "DLP alert was missed the day before",
]

lessons.root_causes = [
    "User clicked on phishing link leading to credential theft",
    "Lack of MFA on affected system",
]

lessons.add_improvement_action(
    action="Implement MFA on all PHI systems",
    owner="IT Security",
    due_date="2024-02-28",
    priority="high",
)

lessons.add_improvement_action(
    action="Enhance phishing training program",
    owner="HR/Training",
    due_date="2024-03-15",
    priority="high",
)

Hands-On Lab: Tabletop Exercise

1

Scenario Setup

Your organization is a regional healthcare system with 3 hospitals and 50 clinics. On Monday at 9:00 AM, your SIEM alerts to unusual activity: a clinical workstation in the ER is making thousands of rapid database queries to the EHR.
2

Exercise Questions

Walk through the incident response:
  1. Detection: What additional information do you need? Who do you notify first?
  2. Classification: Based on initial data, what severity level? What’s your response SLA?
  3. Containment: What are your first 3 containment actions?
  4. Investigation: What logs and evidence do you preserve?
  5. Breach Assessment: 48 hours later, you confirm 15,000 patient records were accessed. Is this a breach? What’s your notification timeline?
3

Document Your Response

Create:
  • Initial incident ticket
  • Classification worksheet
  • Containment checklist
  • Breach risk assessment
  • Notification timeline

Key Takeaways

Preparation is Everything

Incident response is 90% preparation. Build playbooks, train teams, practice regularly.

60-Day Clock

HIPAA breach notification begins at discovery. Know your timeline.

Document Everything

Every action, decision, and finding must be documented for compliance and legal purposes.

Encryption = Safe Harbor

Properly encrypted data with uncompromised keys is NOT a breach. Encrypt everything.

Next Steps