Security model
Pools are encrypted end to end. The server stores ciphertext, hashes, and device public keys — nothing it can read.
Key derivation
A pool is identified by a pool ID and protected by a pool secret. Each client derives separate encryption, authentication, and state-hash keys from the pool secret on the device. The secret and derived keys never leave your browsers. The join code carries the pool ID and secret, so the code is the pool credential.
Encryption
Clients encrypt all pool data with AES-256-GCM before upload. The server receives ciphertext, ciphertext hashes, and keyed state hashes. A separate HMAC key prevents the server from testing guesses about a plaintext state.
Device signing
Each browser generates an Ed25519 key pair when it joins a pool. The client signs every change with the device's private key. The server verifies each signature against the stored public keys, so only pool members can write.
What the server stores
- Ciphertext of pool revisions
- Ciphertext hashes and keyed state hashes
- Device public keys
The server never stores plaintext bookmarks, extension lists, pool secrets, or encryption keys. This holds for the hosted service and for any self-hosted deployment.
What you must protect
The join code is the pool credential. Anyone with the code can read and write the pool. The server cannot reset or recover a pool secret — if every browser leaves a pool, its data cannot be decrypted.
The extension stores the pool secret in local extension storage so it can reconnect after a restart. Encryption protects a server breach. It cannot protect a browser profile or device that an attacker already controls.