Security

CRIE handles Protected Health Information (PHI). Every layer is designed under a hard rule: do not leak PHI, do not log PHI, and do not let an unauthenticated party touch PHI.

Encryption

  • At rest: all free-text PHI columns are stored as BYTEA ciphertext using PostgreSQL pgcrypto (pgp_sym_encrypt) with a key held only in env.
  • In transit: TLS 1.3 everywhere — browser to web, web to API, API to database, API to LLM provider.
  • Searchable identifiers (e.g. MRN) use deterministic HMAC hashes (mrn_hmac) so we can look them up without decrypting.

Authentication

  • Sessions: PASETO v4 local tokens with key-rotation support, in HttpOnly; Secure; SameSite=Strict cookies. Never JWT, never localStorage.
  • Passwords: Argon2id (memory ≥ 19 MiB, t=2, p=1).
  • CSRF: double-submit token on every state-changing request, with safelist for login.

Authorization

Role-Based Access Control on every endpoint, default deny. Three roles: clinician, admin, auditor. Patient-level access is further narrowed by the patient_clinicians assignment table and enforced in the database via Row Level Security policies.

Audit log

Every PHI read and write writes a row to audit_log. The log is append-only and hash-chained: each row carries the hash of the previous row plus its own payload, so any tampering is detectable.

PHI scrubbing in logs

A tracing filter layer redacts known PHI patterns from log events before they are written. The integration test no_phi_in_logs grep-checks captured test output for known markers. Logs use opaque IDs (patient_id, note_id) only.

LLM boundary

  • The default model is local Ollama. No PHI ever leaves the host.
  • When a cloud provider (Anthropic, OpenAI) is enabled, the prompt is de-identified first: names, dates, MRNs are replaced with stable tokens. The mapping never leaves the API process memory.
  • The model output is validated against a JSON schema (Zod / serde). Free-form prose is not trusted.

Threat model

See docs/architecture/threat-model.md in the repo for the full STRIDE pass and mitigation matrix. PRs that change PHI flow are required to update it.