Security
Zero-knowledge by construction. AES-256-GCM in your browser, a key derived from your passphrase through 600,000 rounds of PBKDF2 — the server holds ciphertext it cannot open.
Client-side encryption
Your passphrase derives a 256-bit key with PBKDF2 (600,000 iterations, SHA-256) — well above OWASP 2024 guidance. Provider keys and message history are sealed with AES-256-GCM before they touch the network.
Zero-knowledge by design
The server only ever sees ciphertext. We cannot read your keys, your chats, or your passphrase, and neither can anyone who compromises the database.
No key escrow
There is no recovery backdoor. If you lose your passphrase, your data is unrecoverable. That is the point: nobody but you holds the key.
Per-record IVs
Every encrypted record gets a fresh 96-bit initialization vector, so identical plaintext never produces identical ciphertext.
Independently auditable
The crypto layer is documented end to end with reproducible test vectors. Independent audits are scheduled before general availability.
Rotatable keys
Rotate a provider key or re-key your vault with a new passphrase at any time. Old ciphertext is re-sealed transparently.
The encryption flow
Four steps, all on your device
Passphrase → PBKDF2 600,000 iterations → AES-256-GCM → sealed sync.
- 01
Derive
PBKDF2 · 600,000 iterations · SHA-256
Your passphrase + a unique salt run through PBKDF2 to produce a vault key. The passphrase is never transmitted or stored.
- 02
Encrypt
AES-256-GCM · WebCrypto
Provider API keys and messages are encrypted with AES-256-GCM using the vault key, entirely inside your browser.
- 03
Store
Ciphertext + IV only
Only the ciphertext + IV are sent to the database. The server has no way to decrypt them.
- 04
Decrypt
Re-derived locally, in-memory
On next login, you re-enter your passphrase, the vault key is re-derived locally, and your data is decrypted in-memory.
Strict CSP
frame-ancestors none, nosniff, COOP same-origin, X-Frame DENY.
HSTS preload
HTTPS only, max-age 2 years, includeSubDomains.
Zero-knowledge
Server stores ciphertext only. No escrow, no backdoor.
GDPR-friendly
Opt-in analytics only. Export and delete everything from Settings.
What we store
- Encrypted ciphertext of your provider keys
- Encrypted ciphertext of your conversations
- A unique per-account salt and per-record IVs
- Your email address for magic-link sign-in
What we never store
- Your passphrase or any derivative we could reverse
- Plaintext provider API keys
- Plaintext message content
- Telemetry, trackers, or analytics on your prompts
If our servers are ever breached, your keys and chats stay yours.
Server compromise does not equal data compromise. Because every sensitive byte is sealed in your browser with a key derived from a passphrase only you know, an attacker who exfiltrates our database walks away with ciphertext and salts — meaningless without your passphrase.
Transport
HTTPS only, HSTS preload (max-age 2 years, includeSubDomains). TLS terminated at the edge.
At rest
Supabase Postgres with row-level security; only your authenticated session can read your rows.
In your browser
WebCrypto AES-256-GCM + PBKDF2 600k. No third-party crypto libraries; native primitives only.
Provider calls
Your decrypted key goes directly to the provider over TLS. We do not log prompts or responses.
Auth hardening
Progressive lockout on failed sign-in (5s → 30s → 2m). Caps-Lock warning. Cookies SameSite=Lax + Secure.
Content safety
Strict CSP with frame-ancestors none, X-Content-Type-Options nosniff, COOP same-origin, X-Frame DENY.
No tracking
Vercel anonymous analytics only, and only after you opt in. No marketing cookies, ever.
Responsible disclosure
/.well-known/security.txt sets the contact and the 72-hour acknowledgement window.
Found something we missed? security@sarmalinux.com. We acknowledge within 72 hours and credit reporters in the changelog.