Exit Protocol
Technical deep dive

The security architecture, in full

This page is for engineers, security reviewers, and anyone who wants proof rather than promises. It describes exactly what cryptography runs where, what our servers store, and what an attacker (or we ourselves) could and could not learn from any component. For the plain-language version, see the help page.

Guarantees & threat model

The core property: vault plaintext and the keys that produce it exist only inside the user's browser. The server is an untrusted store of ciphertext. It authenticates you, schedules the switch, and relays sealed boxes; it is never in a position to open them.

We design against these attackers:

AttackerWhat they getOutcome
Network eavesdropperTLS-encrypted traffic carrying already-encrypted payloadsNothing useful, two layers deep
Database thiefCiphertext, salted Argon2id hashes, token digestsCannot read vaults or log in
Malicious or compelled insiderSame database view, plus server codeCannot read vaults without the user's password
Server compromise (full)Database plus environment secretsRecipient-escrowed vault keys only; see §7
Stolen delivery emailA signed one-time linkStill blocked by the email code check

The one attacker no architecture can beat is malware on the user's own device while the vault is unlocked. Section 8 covers how we shrink that window.

The key hierarchy

Everything descends from the master password through one deterministic, client-side pipeline. None of the intermediate values below ever leave the browser except the Auth Token (and that one, by construction, reveals nothing about the others).

  1. 1Master password + email + random salt

    The password is concatenated with the lowercased account email and a random 16-byte per-user salt generated at registration. Binding in the email blocks cross-user rainbow tables; the salt blocks precomputation entirely.

  2. 2Argon2id → Stretched Master Key (32 bytes)

    Argon2id with 64 MiB of memory, 3 iterations, 4 lanes, compiled to WebAssembly and executed in the browser. Memory-hardness is the point: GPU and ASIC password-cracking rigs lose their advantage when each guess costs 64 MiB of RAM.

  3. 3HKDF-SHA256 → two independent keys

    The stretched key is expanded with two different info strings ("enc" and "auth") into a 256-bit Encryption Key and a 256-bit Auth Token. HKDF's extract-and-expand construction makes the two outputs computationally independent: possession of one yields nothing about the other.

  4. 4Encryption Key wraps the Vault Key

    Each vault gets its own random 32-byte Vault Key from the platform CSPRNG. It is wrapped (AES-256-GCM) by the Encryption Key and only that wrapped form is stored server-side. The Encryption Key itself is imported as a non-extractable WebCrypto key and never serialised.

  5. 5Vault Key encrypts every item

    Titles, fields, notes, tags, and file bytes are all separately encrypted with AES-256-GCM under the Vault Key before any network request is made.

Why this chain matters
To read a vault you need the Vault Key. To get the Vault Key you need the Encryption Key. To get the Encryption Key you need the master password and the full Argon2id computation. The server holds none of those at any point, in any form, for any duration.

Authentication without the password

Logging in must not require sending the password, so we send the derived Auth Token instead, and we treat even that token as a secret worth protecting at rest:

  • The password never transits
    The browser sends only the HKDF "auth" output. Because HKDF is one-way and domain-separated, a server that records this value still cannot derive the Encryption Key from it.
  • The token is hashed like a password
    The server stores only an Argon2id hash of the Auth Token (64 MiB, 3 iterations, 4 lanes). A database leak therefore does not even let an attacker authenticate, let alone decrypt.
  • Sessions are short and memory-only
    A successful login yields an HS256 JWT with a 60-minute default lifetime. It is held in a JavaScript variable, never in localStorage or cookies: a page refresh discards it and requires the master password again.
  • Locking is immediate and total
    The Lock button drops the Encryption Key, every Vault Key, and the session token from memory in one step.

Encryption at rest

  • AES-256-GCM everywhere
    Every encrypted field uses AES-256 in Galois/Counter Mode with a fresh random 96-bit IV per encryption. GCM is authenticated: any bit flipped in storage or transit fails the tag check and decryption refuses, so tampering is detected, not silently decoded.
  • Even the metadata is ciphertext
    Item titles, vault names, field labels and values, notes, and tags are all encrypted. The server cannot distinguish a crypto-wallet seed phrase from a cookie recipe, and neither can we.
  • Files use the same key, streamed
    File bytes are encrypted in the browser into a binary blob (12-byte IV followed by ciphertext and tag) before upload. Storage providers see opaque bytes with a random name; storage quotas are measured in encrypted bytes because that is all that exists server-side.
  • Keys are non-extractable
    Working keys are imported as non-extractable WebCrypto CryptoKey objects, so even script running in the page cannot export the raw key material through the WebCrypto API.

The split-key delivery escrow

A dead man's switch has a hard requirement that pure zero-knowledge cannot meet: the system must eventually hand a working key to a recipient without the owner present. We solve it by splitting that capability across two stores that live in different places, with the split performed in the owner's browser:

  1. 1A Delivery Key is born client-side

    When you add a recipient, your browser generates a fresh random 32-byte Delivery Key for them. Each recipient gets their own; revoking one never affects another.

  2. 2The Vault Key is wrapped for them

    Still in your browser, the Vault Key is encrypted under that Delivery Key. This wrapped copy (the escrow) is what the database stores. On its own it is just ciphertext.

  3. 3The Delivery Key is sealed separately

    The Delivery Key travels to the server once and is immediately encrypted with AES-256-GCM under a key derived from a master secret that lives only in the server environment, never in the database.

  4. 4Only delivery reunites the halves

    When the switch fires and a recipient passes both the signed link and the email code check, the server decrypts their Delivery Key and hands both halves to the recipient's browser. The Vault Key is reconstructed and the vault decrypted there, client-side. Vault plaintext still never exists on the server.

Database alone yields
  • Escrowed Vault Keys: ciphertext without their Delivery Keys
  • Delivery Keys: ciphertext without the environment secret
  • No path to any vault content
Environment secret alone yields
  • A decryption key with nothing to decrypt
  • No ciphertext, no escrows, no user data
  • No path to any vault content
The honest caveat
For a vault with recipients, an attacker who fully compromises both the database and the server environment at the same time could combine the halves and recover that vault's key. That is the irreducible cost of unattended delivery, and we would rather state it than hide it. A vault with no recipients has no escrow at all: for it, the system is pure zero-knowledge and no combination of server-side material can ever decrypt it.

Breach scenarios, honestly

The fairest way to evaluate a security design is to assume each layer falls and ask what the attacker actually walks away with:

ScenarioVaults without recipientsVaults with recipients
Database stolenCiphertext only. Unreadable.Ciphertext only. Unreadable.
Environment secrets leakedNothing. No data lives there.Nothing without the database.
Database + environment togetherStill unreadable. No escrow exists.Escrowed Vault Keys recoverable. This is the residual risk described in §5.
Our staff, acting maliciouslyCannot decrypt. The math does not care about job titles.Would need deliberate, combined misuse of both stores; equivalent to the row above.
Recipient's mailbox compromisedn/aAttacker still needs the 6-digit code sent at claim time and has 5 attempts; the owner is emailed at every escalation stage long before delivery.
Your unlocked browser compromisedGame over for that session, as with any client-side encryption product.Same. Lock early, lock often.
The takeaway
For everything you store, the decryption capability either does not exist server-side at all, or exists only as two separated halves that are reunited exclusively for an authenticated recipient after the switch has run its full, loud, multi-stage course.

Known limits & trade-offs

  • No password recovery, ever
    There is no reset flow because there is nothing to reset against. We cannot rebuild what we never had. Losing the master password loses the vault; the dead man's switch itself is the recommended mitigation.
  • The browser is the trust boundary
    Like every end-to-end encrypted web app, the code that does the encrypting is served to your browser. A compromised device or a malicious extension operating while the vault is unlocked defeats any architecture. We shrink the window: 60-minute sessions, memory-only keys, nothing persisted, one-click lock.
  • Escrow is opt-in exposure
    Adding a recipient creates the split-key escrow described in §5. Add recipients only to vaults you actually intend to deliver; vaults without them remain mathematically out of everyone's reach, including ours.
  • Metadata about you exists
    We necessarily know your email address, vault and item counts, encrypted sizes, recipient emails, and switch timing. We never know contents.

Every mechanism above is enforced in code, not in a policy document. The client-side cryptography runs in your own browser where you (or your security team) can inspect exactly what leaves the device.