Security posture
Built for the way PHI actually moves.
ContactFollowUp's application layer does the work HIPAA requires: encryption at rest, immutable audit logs, role-based access, and a service-account model for automation. This page lays out the posture so your Security Officer can review it in one sitting.
Encryption at rest
AES-256-GCM in every PHI column.
PHI fields are stored as *_enc TEXT columns holding AES-256-GCM ciphertext. A raw database dump shows ciphertext only — the application layer with the key is the only path to plaintext.
What's encrypted
Contact (email, phone, DOB, address, notes, names), Activity (body), Appointment (reason, notes, telehealth URL), IntakeSubmission (whole-record), Insurance (member IDs, subscriber, card image URL), Secure Message (subject + body), Calendar Connection (OAuth tokens), Patient Portal password hashes.
Key management
CRM_DATA_KEY (32 bytes, AES-GCM) and CRM_INDEX_KEY (32 bytes, HMAC for blind indexes) come from your secrets store — Azure Key Vault or AWS Secrets Manager. If either is missing the app refuses to start. Key rotation is a documented runbook; PHI is re-encrypted online with zero downtime.
Searchable encryption
Deterministic HMAC blind indexes on email and phone power lookup without ever decrypting the column. The HMAC key is separate from the data key so an attacker who recovers one cannot read the other.
In transit
TLS 1.2+ everywhere. HSTS preload. No mixed-content surface. Internal service-to-service calls run inside a private VPC.
Audit log
Append-only. Every write. Forever.
Every service-layer write emits an AuditLog row with the actor id, actor kind (user · agent · system), action, target, and JSON diff. There is no service path that updates or deletes a row — append-only at the application layer.
Actor model
Three actor kinds: user (a person via cookie session), agent (a service account or automation), and system (a scheduled tick like the workflow runtime). Every row carries an IP and user-agent context when available.
Retention
7 years by default. Configurable per workspace. Audit rows are stored in the same Postgres database, encrypted at rest at the cloud-provider level, and replicated to a separate backup region.
Export
CSV or JSON, scoped to a date range. ADMINs can pull from /app/audit. Service-account holders can pull via GET /api/audit?from=…&to=…&actorKind=…
Tamper-evidence
On the Enterprise tier, audit rows are also written to an append-only S3 / Azure Blob bucket with object-lock enabled. Even a full RDS rollback can't make audit history disappear.
Access control
Role-based access, then per-record sharing.
Two layers: RBAC for what a role can do, and ContactShare for who a specific record is visible to.
Roles
ADMIN · MANAGER · AGENT · READONLY. Capabilities are declared centrally in src/core/rbac.ts. Capability checks happen at every service entry point — the UI cannot grant access the service refuses.
Per-record sharing
ContactShare records grant a specific user READ or WRITE on a specific contact. AGENTs see what they own plus what's shared with them. WRITE shares grant edit access. Sharing actions are audit-logged.
Field-level permissions (Enterprise)
On Enterprise, properties can be tagged with read/write role gates. A field tagged ADMIN-only is invisible to AGENTs — both in the UI and through the API.
Service accounts
Automation runs as a service account with a scoped token. Three reference agents ship with the repo (patient-followup, new-patient-campaign, contact-enrichment). Every action audit-logs as actorKind='agent'.
Authentication
MFA. OIDC SSO. Separate portal sessions.
MFA
TOTP-based MFA with recovery codes, available on every tier. Enrollment lives in /app/settings; enforcement happens at login via short-lived MfaChallenge rows. Recovery codes are hashed at rest.
OIDC SSO
Microsoft and Google OIDC on Pro and Enterprise. SAML on request for Enterprise customers with another IdP. SSO can be enforced (password-disabled) per workspace.
Sessions
Server-side Session rows keyed by an opaque cookie (hn_session). 8-hour idle TTL by default. The patient portal runs on a separate PortalSession table and cookie (hn_portal_session) so a staff compromise can't impersonate a patient and vice versa.
Password policy
bcrypt (cost 12) for hashing. Minimum 12 characters, breach-list check on signup (k-anonymity API). Rate-limited login by IP + email.
BAA & subprocessors
Signed BAAs. Full subprocessor inventory.
ContactFollowUp signs a BAA with every covered customer before any PHI lands. The deployment is responsible for signing BAAs with downstream subprocessors — we surface a tenant-side BAA-management UI so you can track them.
Important: a HIPAA-compliant deployment requires signed BAAs with each subprocessor you use. ContactFollowUp provides the application-layer controls; the BAA contracts themselves are your responsibility per HIPAA's Business Associate provisions.
Incident response
A clear posture, written down before we need it.
Detection
Application logs ship to a separate observability tenant with anomaly detection on auth, audit-row patterns, and rate-limit signals. PHI is redacted at the log boundary.
Notification
On a confirmed PHI-impacting incident, we contact every affected tenant's designated Security Officer within 24 hours. Notification includes scope, suspected cause, and immediate mitigations.
Forensics
Post-incident review within 72 hours: root cause, timeline, contributing factors, and concrete remediation steps. The full review is shared with affected customers.
HIPAA Breach Notification
If the incident meets HIPAA's breach notification threshold, we coordinate with each covered entity to meet the 60-day deadline for HHS and affected-individual notification. We do not notify on your behalf — that's the covered entity's responsibility — but we provide the evidence package within 5 business days.
Shared responsibility
What we do. What you do.
HIPAA compliance is a shared-responsibility model. Here's the line — clearly drawn — so there's no surprise at audit time.
ContactFollowUp provides
Field-level PHI encryption · immutable audit log · RBAC + per-record sharing · MFA + SSO · service-account model · BAA + subprocessor management UI · signed BAA with the covered customer · incident response posture · TLS in transit · data export on demand.
You provide
A signed BAA with each downstream subprocessor you use (we surface a UI to track them) · customer-managed encryption keys stored in Key Vault / Secrets Manager · network restrictions appropriate to your tenant (private networking, IP allow-lists) · a designated Security Officer and incident-response process · workforce training and access reviews.
Get the details
Need the full deck?
We publish a deeper security review — architecture diagrams, encryption flow, threat model, audit log schema — to verified prospects under NDA. Email security@contactfollowup.com or use the form on the contact page.
Move PHI onto a foundation built for it.
Encrypt-at-rest, audit-everything, BAA-ready. From day one.
No credit card. Cancel anytime. 14 days, full access.