How We Keep Your Data Secure
Account & Session Security
- The Flask app boots with a secret key from the environment.
- Creates its SQLite files under the private instance directory.
- Limits session lifetimes.
- Keeps a separate “Hexl” bind for anonymized analytics data.
Signup process:
- Hashes passwords with Werkzeug.
- Enforces a configurable invitation code.
- Checks age requirements.
- Requires passwords to pass a strength policy:
- Character diversity check
- Bans weak values
- Queries HaveIBeenPwned before accepting credentials
Login process:
- Verifies the stored hash.
- Promotes permanent sessions with explicit admin flags.
- Records expiration so the client can re-authenticate before lapse.
Every account also receives a deterministic pseudonym generated with an HMAC “pepper”, preventing exposure of real addresses if pseudonyms leak.
Encryption & Key Management
- User records store only wrapped key material:
- Client-supplied ciphertext of a data encryption key (DEK)
- IV
- KDF salt and parameters
- Hashed password - The plaintext DEK never leaves the browser.
- Personal data lives in zk_sheets:
- AES-GCM ciphertext
- Nonce
- Authenticated data - Updates only via authenticated endpoints that decode base64 payloads before persisting.
- Administrators expose only a public key to clients.
- A user must opt in by storing an admin-wrapped DEK and key identifier before staff can decrypt anything.
- Even then, admin analytics decrypt via an RSA/AES-GCM flow requiring the environment’s private key.
- Gracefully aborts if material is missing, keeping plaintext confined to trusted operators.
Access Control, Consent & Auditing
- Redirects anonymous browsers to login or emits JSON 401s, preventing unauthorized reads.
- Sharing toggles respect user consent:
- Opting out prunes shared analytics rows.
- Clears any stored admin-wrapped DEK so staff can no longer decrypt historical data. - Key account actions (signup, login, saving encrypted sheets) write audit entries to container_activity, creating a trail of sensitive operations.
Input Sanitization & Content Safety
- Free-form text (emails, page content, signup terms, etc.) is sanitized with Bleach.
- Strips HTML/JS before storage or rendering.
- Mitigates stored XSS, even for admin-editable pages.
Operational Safeguards
- Database locations are normalized.
- Legacy files migrated into an isolated “secured” directory.
- A background thread can:
- Copy the SQLite database to an optional backup volume on a fixed cadence.
- Prune snapshots older than seven days.
Summary
Together, these layers provide:
- Strong authentication
- Client-side encryption with wrapped keys
- Explicit consent gates
- Aggressive sanitization
- Operational hygiene
All working in concert to keep user data confidential and resilient.