The Health Insurance Portability and Accountability Act (HIPAA) is the cornerstone of healthcare data protection in the United States. Understanding its requirements is essential before building any healthcare application.
Learning Objectives:
Identify the 18 HIPAA identifiers
Understand covered entities and business associates
# Understanding the differencesclass DataClassification: """ PII (Personally Identifiable Information): - Any data that can identify an individual - Regulated by various laws (GDPR, CCPA, etc.) PHI (Protected Health Information): - PII + Health Information - Regulated by HIPAA ePHI (Electronic PHI): - PHI in electronic form - Subject to HIPAA Security Rule """ @staticmethod def is_phi(data: dict) -> bool: """Check if data contains PHI""" has_health_info = any([ 'diagnosis' in data, 'treatment' in data, 'prescription' in data, 'medical_record' in data, 'lab_results' in data, ]) has_identifier = any([ 'name' in data, 'ssn' in data, 'email' in data, 'phone' in data, 'address' in data, 'dob' in data, 'mrn' in data, ]) return has_health_info and has_identifier# Examplespatient_record = { "name": "John Smith", # Identifier "dob": "1985-03-15", # Identifier "diagnosis": "Hypertension", # Health info "prescription": "Lisinopril" # Health info}# This is PHI ✅anonymous_stats = { "age_range": "40-50", "condition": "Diabetes", "region": "Northeast"}# This is NOT PHI (de-identified) ✅
If you’re building healthcare software, you’ll need a BAA with covered entities:
Copy
# Key elements of a Business Associate Agreementclass BusinessAssociateAgreement: """ Required contractual elements between Covered Entity and Business Associate """ required_provisions = [ "Permitted uses and disclosures of PHI", "Prohibition on unauthorized use/disclosure", "Implementation of appropriate safeguards", "Reporting of security incidents and breaches", "Ensuring subcontractors agree to same restrictions", "Access to PHI for individual rights requests", "Amendment of PHI when requested", "Accounting of disclosures", "Compliance with Security Rule requirements", "Return or destruction of PHI at termination", ] # Cloud Provider BAAs cloud_baa_support = { "AWS": "Available via AWS Artifact", "GCP": "Available via Cloud Console", "Azure": "Available via Trust Center", "Heroku": "Available with Shield plans", "MongoDB Atlas": "Available with dedicated plans", }
Critical: Never handle PHI without a signed BAA in place! This includes:
┌─────────────────────────────────────────────────────────────────────────────┐│ PATIENT RIGHTS UNDER HIPAA │├─────────────────────────────────────────────────────────────────────────────┤│ ││ RIGHT TO ACCESS RIGHT TO AMEND ││ ─────────────── ────────────── ││ • Request copies of PHI • Request corrections ││ • Electronic format if requested • Response within 60 days ││ • Response within 30 days • Denial must be explained ││ • Reasonable fee allowed • Amendment attached if denied ││ ││ RIGHT TO ACCOUNTING RIGHT TO RESTRICT ││ ────────────────── ───────────────── ││ • List of disclosures • Request limits on use ││ • Last 6 years • Not required to agree ││ • Excludes TPO disclosures • Must agree if patient pays ││ out-of-pocket in full ││ ││ RIGHT TO CONFIDENTIAL RIGHT TO COMPLAIN ││ COMMUNICATIONS ───────────────── ││ ───────────────── • File with covered entity ││ • Alternative contact methods • File with HHS OCR ││ • Must accommodate reasonable • No retaliation allowed ││ requests ││ │└─────────────────────────────────────────────────────────────────────────────┘
class BreachAssessment: """ A breach is unauthorized acquisition, access, use, or disclosure of PHI that compromises its security or privacy """ # Exceptions (NOT a breach) exceptions = [ "unintentional_internal", # Workforce member acting in good faith "inadvertent_disclosure", # Internal disclosure, not further used "good_faith_belief", # Unauthorized person couldn't retain data ] # Risk assessment factors def assess_breach(self, incident: dict) -> dict: """Perform 4-factor risk assessment""" return { "nature_of_phi": self._assess_phi_type(incident), "unauthorized_recipient": self._assess_recipient(incident), "phi_actually_acquired": self._assess_acquisition(incident), "risk_mitigated": self._assess_mitigation(incident), } def _assess_phi_type(self, incident): """What types of identifiers and health info were involved?""" high_risk_elements = [ "ssn", "financial_info", "sensitive_diagnoses", "mental_health", "hiv_status", "substance_abuse" ] # More sensitive = higher risk def _assess_recipient(self, incident): """Who received the PHI?""" # Healthcare provider = lower risk # Unknown party = higher risk def _assess_acquisition(self, incident): """Was PHI actually viewed or just transmitted?""" # Encrypted and key not compromised = lower risk # Actually viewed = higher risk def _assess_mitigation(self, incident): """What steps were taken to mitigate harm?""" # PHI recovered and destroyed = lower risk
class BreachNotification: """Required content for breach notifications""" required_content = [ "description_of_breach", # What happened "types_of_phi_involved", # What info was exposed "steps_individuals_should_take", # Self-protection steps "what_entity_is_doing", # Mitigation efforts "contact_procedures", # How to get more info ] def generate_notification(self, breach: dict) -> str: """Generate compliant breach notification""" template = """ NOTICE OF DATA BREACH Date of Notice: {date} What Happened: {description} What Information Was Involved: {phi_types} What We Are Doing: {mitigation_steps} What You Can Do: {protective_steps} For More Information: {contact_info} """ return template.format(**breach)
Remove all 18 identifiers and have no actual knowledge that remaining information could identify an individual.
Copy
class DeIdentification: """HIPAA Safe Harbor de-identification""" identifiers_to_remove = [ "names", "geographic_subdivisions_smaller_than_state", "dates_except_year", # if over 89, use 90+ "phone_numbers", "fax_numbers", "email_addresses", "ssn", "medical_record_numbers", "health_plan_beneficiary_numbers", "account_numbers", "certificate_license_numbers", "vehicle_identifiers", "device_identifiers", "urls", "ip_addresses", "biometric_identifiers", "full_face_photos", "other_unique_identifiers", ] def safe_harbor_deidentify(self, record: dict) -> dict: """Remove all 18 identifiers""" deidentified = record.copy() for identifier in self.identifiers_to_remove: if identifier in deidentified: del deidentified[identifier] # Handle dates - keep only year if "date_of_birth" in deidentified: year = deidentified["date_of_birth"].year if year < 1935: # Over 89 years old deidentified["age_group"] = "90+" else: deidentified["birth_year"] = year del deidentified["date_of_birth"] # Handle geographic data - keep only state if "address" in deidentified: deidentified["state"] = deidentified["address"].get("state") del deidentified["address"] return deidentified