Skip to main content

Documentation Index

Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt

Use this file to discover all available pages before exploring further.

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="schen@healthorg.com",
            backup_person="Mike Rodriguez",
        ),
        IRTeamMember(
            name="James Williams",
            role=IRTeamRole.SECURITY_ANALYST,
            primary_phone="+1-555-0102",
            secondary_phone="+1-555-0103",
            email="jwilliams@healthorg.com",
        ),
        IRTeamMember(
            name="Dr. Emily Foster",
            role=IRTeamRole.PRIVACY_OFFICER,
            primary_phone="+1-555-0104",
            secondary_phone="+1-555-0105",
            email="efoster@healthorg.com",
        ),
        IRTeamMember(
            name="Robert Kim",
            role=IRTeamRole.LEGAL_COUNSEL,
            primary_phone="+1-555-0106",
            secondary_phone="+1-555-0107",
            email="rkim@healthorg.com",
        ),
    ]
)

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": "privacy@organization.com",
                "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

Vendor Management

Manage third-party risk and BAAs

Case Studies

Learn from real HIPAA breaches

Interview Deep-Dive

Strong Answer:
  • Minute 0-5: Validate the alert. Check the SIEM for corroborating evidence — network flow data, database audit logs, IDS alerts. Confirm this is not a false positive (legitimate batch job, scheduled backup to a new IP, misconfigured monitoring). If the data transfer is ongoing and directed to an unknown external IP, treat it as confirmed until proven otherwise.
  • Minute 5-15: Activate the incident response team. Page the IR lead and security analyst (they are the minimum crew for a high-severity after-hours incident). Open the secure communication channel — not email, not Slack on compromised infrastructure. Use the designated out-of-band bridge line. Classify the incident: data exfiltration involving PHI is critical severity based on the classification framework (PHI involved, ongoing threat, potential large volume).
  • Minute 15-30: Containment. Block the destination IP at the network firewall. Do NOT shut down the database server — you need it running for forensic evidence (memory contents, active connections, process tables). Isolate the affected database server from the network except for the forensic workstation. Revoke the credentials being used for the exfiltration — identify the database user, API key, or service account and disable it. If the attack vector is unclear, rotate all database credentials as a precaution.
  • Minute 30-45: Evidence preservation. Take memory dumps of the affected systems before any changes. Capture network packet captures from the firewall and IDS. Snapshot the database audit logs. Take disk images or VM snapshots. Document everything with timestamps — every action, every observation, every decision. This evidence chain is critical for forensics and any legal proceedings.
  • Minute 45-60: Initial scope assessment. How much data was exfiltrated? The network flow data tells you volume (GB transferred). The database audit logs tell you which tables and which patients. Start building the affected patient list. Notify the privacy officer and legal counsel — they need to start the 60-day notification clock assessment. Notify the executive sponsor with a factual summary: what happened, what we did, what we know, what we do not know yet.
Follow-up: The forensic analysis reveals the attacker entered through a vendor’s VPN connection using stolen credentials. The vendor’s BAA requires 24-hour breach notification to you, but they have not notified you. What are the implications?The vendor is in violation of both the BAA and HIPAA. Under HIPAA, a business associate must notify the covered entity of a breach “without unreasonable delay and in no case later than 60 days.” The BAA tightened this to 24 hours, and they failed. The implications: first, we document the vendor’s failure to notify as part of our incident report. Second, we have grounds for BAA termination for cause — their failure to report a security incident is a material breach of the agreement. Third, we report the vendor’s non-compliance to OCR as part of our own breach notification, which may trigger a separate enforcement action against the vendor. Fourth, this goes into our vendor risk assessment as a critical finding, and we immediately evaluate whether to terminate the relationship or impose additional monitoring controls. The vendor’s silence turned what might have been a contained incident (had we been notified early) into a 4-hour exfiltration. Their delay directly increased the harm to patients and our organization.
Strong Answer:
  • This is an insider threat incident with confirmed PHI exfiltration. Severity is high to critical depending on the data involved. The 3-week delay in discovery is itself a finding that needs remediation.
  • Immediate actions: First, verify the scope from audit logs and endpoint DLP (Data Loss Prevention) logs. Exactly which patients, which fields, what data classification? If the records include sensitive PHI (mental health, substance abuse, HIV status), the severity escalates further.
  • Legal and HR engagement: Contact legal counsel immediately. The former employee may have violated HIPAA (criminal penalties apply to individuals who knowingly obtain PHI), their employment agreement, and potentially state data theft laws. Legal will advise on whether to involve law enforcement. Contact HR to review the employee’s termination process — was the exit checklist followed? Was system access revoked on their last day?
  • Recovery attempts: Through legal counsel, send a formal demand letter requiring the former employee to return or certify destruction of all PHI copies. If they retained the data for legitimate purposes (they were a clinician with patient continuity concerns), this might be resolvable. If the intent was malicious (selling data, competitive advantage, revenge), involve law enforcement.
  • Breach assessment: Conduct the four-factor analysis. The PHI was acquired by a specific individual who is identifiable and reachable. The nature of the data matters — 15,000 full patient records is a large breach. If the former employee returns the data and provides a signed attestation of destruction, and you have reason to believe they did not further disclose it, the risk may be mitigated. But 15,000 records almost certainly triggers notification obligations.
  • Remediation: How did they download 15,000 records to USB without detection? Implement DLP controls that block or alert on mass USB transfers of PHI. Disable USB ports on workstations with PHI access. Implement real-time alerting on bulk data exports. Enhance the termination checklist to include immediate access revocation and device return verification.
Follow-up: The former employee claims they downloaded the data because they are a physician and needed it for continuity of care at their new practice. Is this a valid defense?It is a partially valid clinical argument but a completely invalid HIPAA defense. A physician does have a responsibility for continuity of care, but the correct mechanism is a formal records transfer request from the new practice to the old organization, processed through the health information management department with proper authorization and documentation. Downloading 15,000 records to a personal USB drive bypasses every safeguard: no access control review, no audit of what was transferred, no encryption on the USB, no BAA with whatever system the data lands on next. Even with good intentions, the physician violated the minimum necessary standard (they almost certainly did not need all 15,000 records) and created an unsecured copy of PHI outside organizational controls. The intent matters for the criminal penalty tier — “knowingly” versus “for personal gain” — but it does not eliminate the breach. I would work with legal to find a resolution that addresses the physician’s legitimate clinical needs through proper channels while treating the USB download as a reportable incident.
Strong Answer:
  • First, critical clarification: under HIPAA, ransomware is presumed to be a breach. The 2016 HHS guidance states that ransomware constitutes a breach because the attacker has “acquired” the PHI (their malware accessed it to encrypt it), unless you can demonstrate with a preponderance of evidence that the PHI was not accessed, acquired, or viewed. Encryption of data by ransomware is itself unauthorized access.
  • Decision framework for the ransom: the FBI and HHS both recommend against paying. Reasons: payment does not guarantee you get a working decryption key (30-40% of the time, payment leads to no key or a faulty key). Payment funds criminal organizations and incentivizes future attacks. Paying may violate OFAC sanctions if the attacker group is on the sanctions list, creating additional legal liability. And even if you decrypt, you have no assurance the attacker did not also exfiltrate the data — paying the ransom does not undo a breach.
  • Recovery plan: activate the disaster recovery procedure. Restore from the 72-hour-old backups to a clean, isolated environment. Verify the backup integrity before connecting to the network. The 72-hour data gap means you lose 3 days of patient records, orders, and notes. For a hospital, this is clinically significant — engage clinical leadership to manually reconstruct critical orders and medication records from paper or pharmacy systems. For patient safety, the gap reconstruction takes priority over the forensic investigation.
  • Parallel workstreams: (1) Forensics: how did the ransomware enter? Identify the attack vector (phishing email, unpatched vulnerability, compromised credentials), determine the scope of systems affected, and confirm whether data was exfiltrated in addition to being encrypted. (2) Notification: begin the breach notification process. Determine the number of affected patients. If the database served 100,000 patients, all of them are potentially affected. (3) Communication: prepare internal communications (staff need to know how to operate during recovery) and external communications (patients, media, regulators).
  • The 72-hour backup gap is a finding: implement more frequent backups (continuous WAL archiving for PostgreSQL gives point-in-time recovery with near-zero data loss) and test backup restoration quarterly.
Follow-up: The hospital CEO wants to pay the ransom to get back online faster because patient care is being affected. How do you counsel them?I would present the facts without making the decision for them, because this is ultimately a business and patient safety decision. The facts: paying does not guarantee recovery (cite the 30-40% failure rate). Paying may create OFAC liability. If we pay and the key works, we still need to rebuild on clean infrastructure because the attacker had access and may have left backdoors. The estimated time to recover from backup (72 hours of gap, then restoration) might be 24-48 hours. The time to pay, receive a key, and decrypt might also be 24-48 hours — plus the time to verify the decrypted data is not corrupted. So paying may not actually be faster. What WILL get us back online fastest is the backup restoration on clean infrastructure, running in parallel with forensics. If the CEO still wants to pay after hearing this, I would insist on engaging outside counsel and a ransomware negotiation firm, documenting the decision, and performing OFAC screening on the attacker group before any payment. And regardless of whether we pay, we are reporting this as a breach.