Introduction
A former Maryland hospital pharmacist has been indicted for allegedly conducting an 8-year cyber spying campaign, accessing protected health information (PHI) of colleagues and other individuals without authorization. This case exemplifies one of the most persistent and challenging threats in healthcare: the trusted insider with legitimate access abusing privileges for malicious purposes.
The severity cannot be overstated—this wasn't a momentary lapse in judgment but an eight-year sustained campaign of unauthorized surveillance. For healthcare CISOs and security teams, this case underscores the critical gap between perimeter security controls and internal access monitoring. When an authorized user weaponizes their credentials, traditional perimeter defenses offer zero protection. The urgency is clear: without robust insider threat detection and User and Entity Behavior Analytics (UEBA), your organization is vulnerable to similar long-term undetected compromise.
Technical Analysis
Attack Vector: Insider Threat / Privilege Abuse
Affected Systems: Electronic Health Record (EHR) Systems, Healthcare Information Exchanges (HIE), Pharmacy Management Systems
Attack Chain:
- Initial Access: Legitimate credentials obtained through employment position as pharmacist
- Discovery: Querying EHR systems for specific individuals (coworkers, former colleagues, personal contacts)
- Collection: Accessing detailed patient records including prescriptions, diagnoses, and treatment history
- Exfiltration: Exporting or viewing sensitive PHI data for non-medical purposes
- Persistence: Continuing unauthorized access over 8-year period without detection
Exploitation Status: Confirmed active exploitation (insider threat case)
Technical Observables:
- EHR record access patterns exceeding normal clinical workflows
- Queries for patients not under the pharmacist's direct care
- Access to records of employees and former employees
- Off-hours or after-hours access to patient records
- Volume of record access inconsistent with legitimate pharmacy duties
This attack bypasses traditional vulnerability management because it exploits trusted access rather than a software flaw. The CVSS score concept doesn't apply—this is a failure of access governance, monitoring, and behavioral analytics.
Detection & Response
---
title: EHR Access to Non-Patient Records
id: 7a8f3c12-d4e5-4f6b-a9c8-1d2e3f4a5b6c
status: experimental
description: Detects healthcare employees accessing EHR records for patients not under their direct care or assignment. Based on MITRE ATT&CK Technique T1213 - Data from Information Repositories.
references:
- https://attack.mitre.org/techniques/T1213/
author: Security Arsenal
date: 2025/01/15
tags:
- attack.collection
- attack.t1213
- insider-threat
logsource:
product: windows
category: process_creation
detection:
selection:
Image|contains:
- '\epic.exe'
- '\cerner.exe'
- '\allscripts.exe'
CommandLine|contains:
- 'patient_lookup'
- 'record_query'
- 'phi_access'
ParentImage|contains:
- '\explorer.exe'
filter_legitimate:
CommandLine|contains:
- 'current_patient'
- 'admitted_patients'
- 'pharmacy_queue'
condition: selection and not filter_legitimate
falsepositives:
- Legitimate cross-coverage queries
- Emergency department lookups
- Quality assurance access
level: medium
---
title: Suspicious EHR Data Export Activity
id: 9b2g1h34-e5f6-4g7c-b8d9-2e3f4a5b6c7d
status: experimental
description: Detects potential data exfiltration from EHR systems via print, email, or export functions by healthcare staff. MITRE ATT&CK T1567 - Exfiltration Over Web Service.
references:
- https://attack.mitre.org/techniques/T1567/
author: Security Arsenal
date: 2025/01/15
tags:
- attack.exfiltration
- attack.t1567
- insider-threat
logsource:
product: windows
category: file_event
detection:
selection:
TargetFilename|contains:
- '\Downloads\\'
- '\Desktop\\'
TargetFilename|endswith:
- '.pdf'
- '.csv'
- '.xlsx'
- '.docx'
SourceImage|contains:
- '\epic.exe'
- '\cerner.exe'
- '\allscripts.exe'
timeframe: 1h
condition: selection | count() > 10
falsepositives:
- Legitimate report generation
- Authorized data exports
level: high
---
title: After-Hours EHR Access Anomaly
id: 1c3d4e5f-6a7b-8c9d-0e1f-2a3b4c5d6e7f
status: experimental
description: Detects EHR system access outside of normal working hours which may indicate unauthorized surveillance. Based on MITRE ATT&CK T1078 - Valid Accounts.
references:
- https://attack.mitre.org/techniques/T1078/
author: Security Arsenal
date: 2025/01/15
tags:
- attack.privilege_escalation
- attack.t1078
- insider-threat
logsource:
product: windows
category: process_creation
detection:
selection_time:
TimeGenerated:
- weekday:
start: '18:00:00'
end: '23:59:59'
- weekend:
start: '00:00:00'
end: '23:59:59'
selection_app:
Image|contains:
- '\epic.exe'
- '\cerner.exe'
- '\meditech.exe'
selection_command:
CommandLine|contains:
- 'patient_record'
- 'chart_review'
- 'demographics'
condition: all of selection_*
falsepositives:
- On-call pharmacy staff
- Emergency response teams
- Resident physicians
level: medium
// KQL Hunt Query: Excessive EHR Record Access Patterns
// Hunt for users accessing unusually high volumes of patient records
let TimeRange = 7d;
let EHRApplications = dynamic(["epic.exe", "cerner.exe", "meditech.exe", "allscripts.exe", "mckesson.exe"]);
let SuspiciousKeywords = dynamic(["patient_lookup", "record_query", "demographics", "phi_access", "chart_review"]);
let NormalAccessThreshold = 50; // Adjust based on baseline
DeviceProcessEvents
| where Timestamp >= ago(TimeRange)
| where FileName in~ EHRApplications
| where ProcessCommandLine has_any (SuspiciousKeywords)
| summarize RecordAccessCount = count(), AccessedPatients = dcount(ProcessCommandLine) by AccountName, DeviceName, bin(Timestamp, 1h)
| where RecordAccessCount > NormalAccessThreshold
| extend RiskScore = iff(RecordAccessThreshold > NormalAccessThreshold * 2, "High", "Medium")
| project Timestamp, AccountName, DeviceName, RecordAccessCount, AccessedPatients, RiskScore
| order by RecordAccessCount desc
| join kind=leftouter (
IdentityInfo
| project AccountName, Department, JobTitle
) on AccountName
| where JobTitle !contains "pharmacy" // Flag non-pharmacy staff accessing pharmacy-like queries
// KQL Hunt Query: Coworker/Employee Record Access Pattern
// Detect users querying records of other employees
let TimeRange = 30d;
// In production, this would reference your HR database of employee identifiers
let EmployeeIdentifiers = dynamic(["EMP", "STAFF", "DOCTOR", "NURSE", "ADMIN"]);
DeviceProcessEvents
| where Timestamp >= ago(TimeRange)
| where FileName in~ ("epic.exe", "cerner.exe", "meditech.exe")
| extend RecordIdentifier = extract(@'patient_id\s*=\s*[\"\']?([\w-]+)', 1, ProcessCommandLine)
| where RecordIdentifier has_any (EmployeeIdentifiers)
| summarize AccessedEmployeeRecords = dcount(RecordIdentifier), AccessEvents = count() by AccountName, bin(Timestamp, 1d)
| where AccessedEmployeeRecords > 0
| project Timestamp, AccountName, AccessedEmployeeRecords, AccessEvents
| order by AccessedEmployeeRecords desc
-- Velociraptor VQL: Hunt for EHR Application Artifacts and Evidence
-- Collect process execution history and EHR application logs
SELECT * FROM foreach(
row={
SELECT ProcessName, Pid, Ppid, StartTime, Username, CommandLine
FROM pslist()
WHERE ProcessName =~ 'epic.exe'
OR ProcessName =~ 'cerner.exe'
OR ProcessName =~ 'meditech.exe'
},
query={
SELECT
ProcessName,
Pid,
StartTime,
Username,
CommandLine,
Mtime as LastModified,
Size
FROM glob(globs='\Users\' + Username + '\AppData\Local\' + ProcessName + '\Logs\*.log')
}
)
-- Hunt for suspicious EHR data exports in user directories
SELECT FullPath, Size, Mtime, Atime, Btime, Mode
FROM glob(globs='C:\Users\*\Downloads\*{patient,record,phi,medical}*.csv')
UNION SELECT FullPath, Size, Mtime, Atime, Btime, Mode
FROM glob(globs='C:\Users\*\Desktop\*{patient,record,phi,medical}*.pdf')
-- Network connections from EHR applications to external destinations
SELECT Pid, RemoteAddress, RemotePort, State, StartTime
FROM netstat()
WHERE Pid IN (
SELECT Pid FROM pslist()
WHERE ProcessName =~ 'epic.exe'
OR ProcessName =~ 'cerner.exe'
)
AND RemoteAddress NOT IN ("127.0.0.1", "::1")
AND RemotePort NOT IN (443, 80) // Exclude standard web traffic
# PowerShell Script: Healthcare Insider Threat Hardening and Verification
# Run as Administrator on domain controllers or EHR management servers
Write-Host "[+] Starting Healthcare Insider Threat Hardening Check" -ForegroundColor Cyan
# 1. Verify EHR Application Logging is Enabled
Write-Host "`n[+] Checking EHR Application Logging Configuration..." -ForegroundColor Yellow
$ehrApps = @("Epic", "Cerner", "Meditech", "Allscripts", "McKesson")
foreach ($app in $ehrApps) {
$logPath = "HKLM:\SOFTWARE\$app\Logging"
if (Test-Path $logPath) {
$auditEnabled = (Get-ItemProperty -Path $logPath -ErrorAction SilentlyContinue).AuditLogLevel
Write-Host " [-] $app Logging: $auditEnabled" -ForegroundColor $(if($auditEnabled -ge 2){"Green"}else{"Red"})
}
}
# 2. Check for Privileged Group Membership Anomalies
Write-Host "`n[+] Checking for Privileged EHR Access Groups..." -ForegroundColor Yellow
$privGroups = @("EHR-Admins", "EHR-SuperUsers", "EMR-FullAccess", "PHI-All-Access")
foreach ($group in $privGroups) {
try {
$members = Get-ADGroupMember -Identity $group -ErrorAction Stop | Select-Object -ExpandProperty Name
Write-Host " [-] $group has $($members.Count) members" -ForegroundColor Cyan
if ($members.Count -gt 10) {
Write-Host " [!] WARNING: High number of privileged users detected" -ForegroundColor Red
}
} catch {
Write-Host " [-] Group $group not found or inaccessible" -ForegroundColor Gray
}
}
# 3. Verify Audit Policies for PHI Access
Write-Host "`n[+] Verifying Advanced Audit Policy for Object Access..." -ForegroundColor Yellow
$auditPolicy = auditpol /get /subcategory:"File System" 2>&1
if ($auditPolicy -match "Success and Failure") {
Write-Host " [-] File System auditing: ENABLED" -ForegroundColor Green
} else {
Write-Host " [!] File System auditing: NOT ENABLED" -ForegroundColor Red
}
# 4. Check for Recently Created EHR Data Exports
Write-Host "`n[+] Scanning for Recent EHR Data Exports (Last 7 Days)..." -ForegroundColor Yellow
$cutoffDate = (Get-Date).AddDays(-7)
$exportPaths = @(
"C:\Users\*\Downloads\*.csv",
"C:\Users\*\Downloads\*.xlsx",
"C:\Users\*\Desktop\*.pdf",
"C:\Temp\*\*.csv"
)
$suspiciousExports = foreach ($path in $exportPaths) {
Get-ChildItem -Path $path -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -gt $cutoffDate -and $_.Length -gt 100KB }
}
if ($suspiciousExports) {
Write-Host " [!] Found $($suspiciousExports.Count) suspicious recent exports" -ForegroundColor Red
$suspiciousExports | Select-Object FullName, LastWriteTime, Length | Format-Table -AutoSize
} else {
Write-Host " [-] No suspicious recent exports found" -ForegroundColor Green
}
# 5. Generate Recommendation Report
Write-Host "`n[+] GENERATING HARDENING RECOMMENDATIONS..." -ForegroundColor Yellow
$recommendations = @(
"Implement User and Entity Behavior Analytics (UEBA) for EHR access",
"Enable quarterly access reviews for EHR privileged groups",
"Configure automated alerts for off-hours PHI access",
"Implement role-based access control (RBAC) with principle of least privilege",
"Enable comprehensive audit logging for all EHR record access",
"Deploy Data Loss Prevention (DLP) for PHI export channels",
"Establish separation of duties between clinical and administrative access",
"Implement automated monitoring for coworker/employee record access"
)
$recommendations | ForEach-Object { Write-Host " [+] $_" -ForegroundColor White }
Write-Host "`n[+] Hardening Check Complete" -ForegroundColor Green
Remediation
Immediate and sustained actions are required to prevent similar insider threat campaigns:
1. Implement UEBA for Healthcare Environments
- Deploy User and Entity Behavior Analytics (UEBA) specifically tuned for EHR access patterns
- Establish baselines for normal record access volume per role (pharmacist, nurse, physician)
- Configure alerts for anomalies: >3 standard deviations from baseline access patterns
- Vendor Recommendations: Microsoft Sentinel UEBA, Splunk UBA, Exabeam, Securonix
2. Enforce Least Privilege Access
- Conduct immediate access review for all EHR privileged groups (EHR-Admins, SuperUsers)
- Remove standing access—implement just-in-time (JIT) privilege elevation for admin functions
- Implement attribute-based access control (ABAC) for PHI: limit access to assigned patients only
- Require documented business justification for cross-departmental record access
3. Enable Comprehensive EHR Audit Logging
- Epic Systems: Enable "Hyperspace Audit Logging" at level 3 or higher
- Cerner PowerChart: Enable "Clinical Audit" and "Access Audit" logging
- Meditech: Enable "User Activity Log" with detailed field capture
- Forward all EHR logs to SIEM (Sentinel, Splunk) with retention minimum 7 years per HIPAA
4. Implement Automated Access Reviews
- Schedule quarterly certification reviews for EHR access rights
- Automate revocation of access for terminated employees within 4 hours via HR system integration
- Require manager approval for continued access after role change
5. Deploy PHI-Specific DLP Controls
- Implement Microsoft Information Protection (MIP) or similar for PHI classification
- Block unauthorized export channels (USB, personal email, cloud storage)
- Require approved workflows for any legitimate data export
Official Resources & Deadlines
- HHS OCR HIPAA Security Rule: https://www.hhs.gov/hipaa/for-professionals/security/
- NIST SP 800-53 (AC-2, AU-6, AU-12): Access Control and Audit Logging controls
- CISA Insider Threat Mitigation Guide: https://www.cisa.gov/insider-threat-mitigation
- Healthcare Sector Specific Implementation Guide (SSIG): Review and align controls
Compliance Implications
- This violation falls under HIPAA Breach Notification Rule and Civil Monetary Penalties
- Potential fines: $50,000-$1.5 million per violation category
- State breach notification laws may apply (Maryland Personal Information Protection Act)
Related Resources
Security Arsenal Healthcare Cybersecurity AlertMonitor Platform Book a SOC Assessment healthcare Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.