← Back to home

Security

How your vault stays private

The short version on the home page is true. Here's what it actually means, in the detail you'd want before trusting anything with the things that matter to you.

Encryption

Locked at the field, not just the door

The sensitive details you record are encrypted at the individual field level using AES-256-GCM — the same authenticated encryption trusted for protecting data at rest across the industry. Encryption happens before the value is written, so what lands in the database is ciphertext, not readable text.

Keys are versioned. When a key is rotated, the older versions are kept for the lifetime of the data they protected, so a rotation never strands an older record or leaves anything unreadable. Every encrypted value carries the version of the key that sealed it.

Uploaded files — photos and documents — are protected the same way, with an extra layer. Each upload gets its own one-time data key that encrypts the file bytes with AES-256-GCM, and that data key is then wrapped with the server-held master key and bound to your vault. A wrapped key from one vault cannot unwrap under another: the mismatch fails authentication rather than yielding readable bytes.

Isolation

Your vault, and only yours

Every vault lives behind its own URL with its own login. There is no shared space where one person's items sit next to another's.

Underneath, isolation is enforced by Postgres row-level security. Every query against vault data is automatically scoped to a single vault — the database refuses to return rows from any other. Cross-vault access isn't merely blocked in the application code; it isn't possible at the data layer, which is the layer that actually holds your information.

The operator boundary

The console runs on service signals, not your vault

Running a service means seeing that it's healthy — how many vaults exist, whether things are working. That doesn't require reading what you've stored, so the super-admin console is built to work without it.

The console reads usage signals only: counts and timings, never the contents of any vault and never record-level or monetary data. That's reinforced structurally — the tables the console reads are separate from the tables that hold your items, and item data is reachable only inside a single vault's isolated scope, enforced for the application by Postgres row-level security.

In the interest of honesty: this is not an arrangement where we are technically incapable of ever accessing your data. The master encryption key is held on our servers, and the database has an administrative role that can bypass row-level security. The guarantee we make is narrower and truer — the console is designed to run on service signals rather than your records, not that reaching those records is impossible.