HIPAA-compliant PHI detection + redaction for outbound patient messaging.
Catches procedure codes (CDT/CPT), tooth numbers, diagnosis terms, chart references, and insurance IDs before they leave your server. Extracted from production use at usdpr. (US Dental Patient Recovery).
HIPAA's Privacy Rule permits SMS/email to patients with proper consent — as long as the message body doesn't carry clinical detail. In practice, every dental-tech team I've talked to implements this as "operator policy: don't put PHI in messages." Policies don't stop 2am typos. Enforcement has to be in code, at the query layer.
This library wraps your send function with a decorator that rejects any message containing PHI patterns. @scrubbed.
pip install usdpr-phi-scrubberfrom usdpr_phi_scrubber import scrubbed, PHIViolation
@scrubbed
def send_patient_sms(patient_id: str, body: str) -> None:
twilio_client.messages.create(to=patient_id, body=body, from_=OUR_NUMBER)
send_patient_sms("p_123", "Time for your cleaning tomorrow at 10am") # OK
send_patient_sms("p_123", "Your root canal on tooth #14 is ready") # raises PHIViolation
send_patient_sms("p_123", "Crown prep for D2740 on Tuesday") # raises PHIViolation| Category | Example | Regex source |
|---|---|---|
| CDT codes | D0150, D2740, D7210 |
ADA 2024 Code on Dental Procedures |
| CPT codes | 99213, 41899 |
AMA 2024 CPT |
| ICD-10 | K02.1, M79.3 |
CDC ICD-10-CM 2024 |
| Tooth numbers | tooth #14, #3-5, UR1 |
Universal + Palmer numbering |
| Diagnosis terms | root canal, crown prep, extraction, periodontitis |
HHS phi gazetteer + clinical dict |
| Insurance IDs | member ID 1234567, group 5678 |
Common EHR exports |
| Chart references | chart #12345, MRN 67890 |
PMS export patterns |
Single-pass regex + string match. ~0.4ms per message on M1 (benchmarked). Zero allocation overhead; no deps beyond stdlib.
from usdpr_phi_scrubber import Scrubber
scrubber = Scrubber()
scrubber.add_pattern(r"\bclaim-\d{6}\b", kind="claim_id")
scrubber.scrub("Your claim-123456 is approved") # raises PHIViolationEvery violation carries the pattern matched + the offending substring:
try:
send_patient_sms("p_123", "Tooth #14 extraction scheduled")
except PHIViolation as e:
log.error("phi_blocked", pattern=e.pattern, match=e.match_text, kind=e.kind)pip install -e .[dev]
pytestPasses 187 tests covering every pattern family + 40 edge cases.
- A HIPAA compliance program (you still need BAAs, encryption, audit logs, access controls)
- A medical NER system (use ScispaCy or MedSpaCy for that)
- A substitute for training (operators still need to know what they can and can't say)
Apache-2.0. Patent-grant clauses apply. Built and maintained by Colin Smith at usdpr. — a patient reactivation SaaS for US dental practices.
If you're running a dental practice and fighting the reactivation leak: run the ROI calculator or read The State of Dental Patient Reactivation 2026.