Abundey Logo

Privacy & zero-knowledge

What the encryption actually does, what our servers can and cannot see, and where the guarantee stops.

"Zero-knowledge" is a claim that is easy to make and easy to overstate, so this page is specific about what Abundey does, and equally specific about where it stops.

The short version: everything you save is encrypted in your browser before it is sent, with a key we never receive. Our servers store ciphertext they cannot read. Chat is stronger still — it never reaches the network at all.

Chat never leaves the device

The assistant runs on your own GPU (see Models). There is no inference server, so prompts and replies have nowhere to travel. The only network call in the entire chat flow is the one-time model download.

Transcripts persist the same way everything else does: as an encrypted vault blob, sealed on your device before it syncs. When the vault is locked, chat still works — it simply does not persist.

The vault: one key, several ways in

Your data is encrypted with a single data encryption key (DEK), generated randomly in your browser. The DEK is never stored anywhere in the clear. Instead it is stored wrapped — encrypted by a second key derived from each way you have chosen to unlock.

That indirection is what makes the vault practical. Adding an unlock method adds a wrapped copy of the same DEK; removing one deletes that copy. The DEK itself never changes, so your data is never re-encrypted.

The wraps live together in a keyring, itself just another vault blob. Two unlock methods are live today:

  • Recovery key — a 256-bit random secret, generated on your device and shown to you as a 24-word phrase. This is the floor: it always exists, and it is the one that works on a device that has never seen your vault.
  • Device PIN — a convenience wrap for a device you already trust, derived with PBKDF2. It unlocks faster; it does not replace the recovery key.

Passkey unlock is designed and reserved in the code, but is not shipped yet.

Payloads are encrypted with AES-256-GCM, with a fresh random nonce for every write. All of it runs through the browser's built-in WebCrypto — we do not ship our own cipher implementations.

What our servers actually store

The vault API (backend/src/routes/vault.ts) accepts and returns exactly four fields per blob: ciphertext, nonce, version, and updatedAt, keyed by owner and blob kind. There is no decrypt path in the backend, because there is no key there to decrypt with.

What that leaves visible to us, and we would rather say it than let you discover it:

  • Which kinds of blob you have — family, projection, keyring, chat
  • How large each blob is
  • When you last wrote, and how many times you have written (the version counter)
  • Your email, and which family office you belong to

So we can tell that you use projections and roughly how much you have in there. We cannot tell what any of it says.

Where the guarantee stops

This protects you against a database breach, a stolen backup, a subpoena served on our storage, or a passive compromise of our servers. In all of those, what an attacker gets is ciphertext, nonces, wrapped keys and the metadata above.

It does not make us untrustworthy-proof. We serve the JavaScript that performs the encryption in your browser. An operator willing to ship malicious code to a targeted user could capture a key before it is used. Every browser-delivered encrypted app shares this property, and no amount of cryptography inside the app removes it.

The honest framing is zero-knowledge at rest, and against breach — not trustless.

Recovery

Your recovery key is generated on your device and is never transmitted to us, which means we cannot reset it, email it to you, or recover it on your behalf.

Losing the recovery key means losing the data. That is a design decision, not a gap. A backdoor for you is a backdoor for anyone who can compel us to use it. Write the phrase down and keep it somewhere physical.

On this page