← Back to home

How We Protect Your Data

This project is in Beta! It's being actively developed by a team of volunteers and may break and change at any time. We're actively working on improving security measures to make it as robust as possible.

You can read about our ongoing efforts below.

Your information is deeply personal. We built this vault to be as private as a handwritten note locked in a safe — except it's protected by military-grade encryption that even we cannot break.

We cannot read your data. We cannot recover your passphrase. Without your passphrase, your data is cryptographically unrecoverable — even for us.

Everything Happens in Your Browser

This is the most important thing to understand: all sensitive operations happen entirely in your browser. Our servers never see your passphrase, your data, or your encryption keys in unencrypted form.

OperationWhere It Happens
Main passphrase generationYour browser
Read-only passphrase generationYour browser
Write passphrase generationYour browser
Signing keypair generation (Ed25519)Your browser
Key derivation (Argon2id)Your browser
Encryption (XChaCha20-Poly1305)Your browser
DecryptionYour browser
Digital signing (Ed25519)Your browser
Vault ID derivationYour browser

Passphrases are generated using crypto.getRandomValues(), the Web Cryptography API built into every modern browser. This is a cryptographically secure random number generator — the same one used by password managers and banking apps.

The server's only job is to store encrypted blobs and return them when requested. It never sees plaintext, never sees passphrases, and has no way to decrypt anything.

The Two-Tier Key Architecture

Your vault uses a sophisticated two-tier encryption system. Understanding this architecture helps explain why your data is so secure.

The Security Chain
Your Vault Data
contacts, accounts, documents...
↓ encrypted with
DEK (Data Encryption Key)
32 random bytes, unique to your vault
↓ encrypted ("wrapped") with
KEK (Key Encryption Key)
derived from passphrase via Argon2id
↓ derived from
Your Passphrase
the only secret you need to protect

Why two tiers? This architecture provides several benefits:

  • Passphrase changes are fast: If you could change your passphrase, we'd only need to re-wrap the DEK with the new KEK — not re-encrypt the entire vault.
  • Read-only keys work independently: Each read-only passphrase wraps the same DEK with a different KEK. Revoking one doesn't affect others.
  • Defense in depth: An attacker would need to unwrap the DEK first, then decrypt the data — two separate cryptographic operations.

What If Our Server Is Compromised?

Let's be explicit about what an attacker would get if they completely compromised our database:

What an attacker gets:
  • Encrypted vault data (ciphertext)
  • Wrapped DEK (the DEK encrypted with your KEK)
  • Salt and nonces (parameters for decryption)
  • Passphrase hashes (for authentication)
What an attacker still needs:
  • Your passphrase — without it, they cannot derive the KEK, cannot unwrap the DEK, and cannot decrypt your data.

The wrapped DEK is useless without the passphrase. It's encrypted with XChaCha20-Poly1305, the same algorithm protecting your vault data. To unwrap it, an attacker would need to derive your KEK, which requires knowing your passphrase.

This is where Argon2id matters. Even if an attacker tries to brute-force your passphrase, Argon2id makes each guess extremely expensive: it requires 256 MB of RAM and multiple CPU seconds per attempt. This makes large-scale password cracking impractical, even with specialized hardware.

How Read-Only and Write Keys Work (In Detail)

Both read-only and write keys are applications of the two-tier architecture. They allow you to share access to your vault with different permission levels:

Read-Only Keys

When you create a read-only key:

  1. A new passphrase is generated in your browser (same format as the main passphrase)
  2. A new KEK is derived from that passphrase using a fresh random salt
  3. Your vault's DEK is wrapped with this new KEK
  4. The wrapped DEK is stored on our server (along with the salt and a hash for identification)

Write Keys

Write keys work similarly but include an additional cryptographic component for write access:

  1. A new passphrase is generated in your browser (same format as the main passphrase)
  2. A new KEK is derived from that passphrase using a fresh random salt
  3. Your vault's DEK is wrapped with this new KEK (for decryption)
  4. Your vault's signing private key is wrapped with this new KEK (for write access)
  5. Both wrapped keys are stored on our server (along with the salt and a hash for identification)
Multiple Keys, Same DEK
Your Vault Data
(encrypted)
DEK
(same for all keys)
↓ wrapped by ↓
Wrapped with
KEK₁
(Main)
Wrapped with
KEK₂
(RO Key)
Wrapped with
KEK₃
(Write Key)
↓ derived from ↓
Main
Passphrase
Read-Only
Key #1
Write
Key #1

When someone uses a read-only or write key to access your vault:

  1. They enter the passphrase (read-only or write) in their browser
  2. The browser hashes the passphrase and sends the hash to our server
  3. Our server finds the matching key by its hash
  4. For read-only keys: The server returns that key's wrapped DEK and salt
  5. For write keys: The server returns that key's wrapped DEK, wrapped signing key, and salt
  6. The browser derives the KEK from the passphrase + salt
  7. The browser unwraps the DEK and decrypts the vault
  8. For write keys: The browser also unwraps the signing private key and stores it in memory for signing updates

Important: Each read-only and write key has its own wrapped copy of the DEK (and signing key for write keys). When you revoke a key, we delete those wrapped copies. The passphrase becomes useless because there's no longer a wrapped DEK for it to unwrap.

Cryptographic Write Enforcement

To ensure that only authorized users can modify your vault, we use Ed25519 digital signatures. When you create a vault, a single master signing keypair is generated in your browser:

  1. Signing keypair generation: An Ed25519 keypair is created (public and private keys). This is the only signing keypair for your vault — all write operations use this same keypair.
  2. Private key wrapping: The signing private key is wrapped with your master KEK and stored encrypted in your vault. When you create write keys, this same master signing private key is wrapped with each write key's KEK and stored on the server.
  3. Public key storage: The signing public key is stored on our server (unencrypted, for verification). This single public key is used to verify signatures from both the master passphrase and all write keys.

Key insight: There is one master signing keypair per vault. Write keys don't generate their own keypairs — they receive a wrapped copy of the master signing private key. This ensures all write operations (whether from the master passphrase or any write key) are cryptographically equivalent and can be verified using the same public key.

When you save changes to your vault, the browser:

  1. Creates a canonical signature payload containing the vault ID, timestamp, encryption nonce, ciphertext, wrapped key, and version
  2. Signs the payload using your signing private key (Ed25519 detached signature)
  3. Sends both the signature and the signed data to the server

The server then:

  1. Verifies the signature using the stored public key (constant-time verification)
  2. Checks timestamp freshness (prevents replay attacks — signatures expire after 5 minutes)
  3. Ensures data integrity (the signed data must match the request data)
  4. Only accepts the update if all checks pass

Why this matters: Read-only keys don't have access to the signing private key. Even if someone with a read-only key somehow bypassed client-side checks, their write attempts would be cryptographically rejected by the server because they cannot produce a valid signature. This provides the strongest possible guarantee that read-only access cannot be escalated to write access.

Write Key Architecture
Your Vault Data
(encrypted)
DEK
(for decryption)
↓ wrapped by ↓
Write Key KEK
(derived from write passphrase)
↓ wraps both ↓
Wrapped
DEK
Wrapped
Signing Key
↓ stored on server ↓
Server Storage
Wrapped DEK + Signing Key

Why Read-Only and Write Keys Can't Decrypt Exported Bundles

When you export your encrypted vault data, the bundle includes only the main passphrase's wrapped DEK:

// Exported encrypted bundle contains:
ciphertext // encrypted vault data
nonce
wrappedKey // DEK wrapped with MAIN passphrase's KEK
wrappedKeyNonce
kdfSalt // salt for MAIN passphrase's KEK

Read-only and write passphrases have different wrapped DEKs with different salts, stored on our server. Those aren't included in the export. So a read-only or write passphrase holder:

  • Can decrypt online (server provides their specific wrapped DEK)
  • Cannot decrypt the exported bundle (it uses the main passphrase's wrapped DEK)

This is a feature, not a limitation. It means shared access (read-only or write) is truly limited to online access through our service. If you share a code, that person can access your vault online but cannot create an offline backup using the exported bundle.

End-to-End Encryption Summary

When you create a vault, we generate a unique passphrase with approximately 73 bits of entropy — strong enough to resist brute-force attacks. This passphrase is used to derive an encryption key using Argon2id, a memory-hard key derivation function that's resistant to GPU and ASIC attacks. Your data is then encrypted using XChaCha20-Poly1305, a modern authenticated encryption algorithm used in secure messaging apps and cryptographic protocols worldwide.

Zero Tracking. Zero Analytics.

We don't use Google Analytics. We don't use Facebook Pixel. We don't use any third-party tracking scripts. We don't fingerprint your browser.

Note on IP addresses: Like most web services, our servers log IP addresses for security and rate limiting purposes. However, IP addresses are also included in your vault's encrypted activity history, so you can see where access to your vault originated from. This history is encrypted and only visible to people with access to your vault.

There are no cookies tracking your behavior. There are no invisible pixels watching what you do. There is no advertising network building a profile of you.

We don't even know how many people use this service, because we don't count. Your privacy is more important than our metrics.

No Account Required

You don't need to give us your email address. You don't need to create a username. You don't need to verify your identity. Your passphrase is your only key, and your only connection to your vault.

This means there's no "forgot password" button, no password reset email, and no way for us to help you if you lose your passphrase. But it also means there's no way for anyone — including us — to access your data without it.

Activity History

Every action in your vault is logged — when it's opened, when data is changed, when read-only or write keys are created or revoked, and when someone accesses it with a shared code. This activity history is stored encrypted within your vault, so only you (and those you share access with) can see it.

The activity log shows timestamps, what changed, the IP address of the device that performed the action, and whether access was via the main passphrase, a read-only code, or a write code (including the name of the key used). This helps you keep track of who accessed your information, when, and from where.

Complete Technical Specifications

Encryption AlgorithmXChaCha20-Poly1305 (authenticated encryption)
Key DerivationArgon2id (memory-hard, GPU/ASIC resistant)
Argon2id Parametersopslimit=3, memlimit=268435456 (256 MB)
Key Size256 bits (32 bytes)
Nonce Size192 bits (24 bytes), regenerated on each save
Salt Size128 bits (16 bytes), unique per vault and per read-only key
Passphrase Format6 words + 4 digits (e.g., sunset-harbor-crystal-wisdom-river-falcon-7284)
Passphrase Entropy~73 bits (60 bits from words + 13 bits from number)
Passphrase IdentificationBLAKE2b hash (zero-knowledge — we never see the passphrase)
Vault ID DerivationBLAKE2b hash of passphrase with domain separator
Key WrappingTwo-tier hierarchy: KEK wraps DEK, DEK encrypts data
Read-Only KeysSeparate KEK per code, same DEK; independently revocable
Write KeysSeparate KEK per code, same DEK + wrapped signing key; independently revocable
Digital SignaturesEd25519 (for write access enforcement)
Signature AlgorithmEd25519 detached signatures (constant-time verification)
Replay ProtectionTimestamp freshness check (5-minute window, 60-second clock skew tolerance)
Cryptography Librarylibsodium (libsodium-wrappers-sumo)
Memory SafetyAll sensitive keys zeroed from memory after use

We use libsodium, one of the most widely-used and thoroughly-audited cryptographic libraries available. It's the same library used by companies like Cloudflare, Discord, and many others for their security-critical operations.

Rate Limiting & Abuse Prevention

To protect against brute-force attacks and abuse, we implement rate limiting on all API endpoints. This prevents attackers from making unlimited guesses at vault IDs or overwhelming our servers with requests.

Security Headers

We enforce strict security headers including Content Security Policy (CSP), HTTP Strict Transport Security (HSTS), and protection against clickjacking and MIME-type attacks. These headers provide defense-in-depth against common web vulnerabilities.

What We Store

Our database contains the following for each vault:

  • A random vault ID (derived from your passphrase via BLAKE2b hash)
  • The encrypted data (ciphertext — unreadable without your passphrase)
  • The wrapped DEK (the data encryption key, encrypted with your KEK)
  • Salts and nonces needed for decryption (useless without the passphrase)
  • Passphrase hashes for authentication (one-way BLAKE2b, cannot be reversed)
  • Wrapped DEKs for each read-only key (useless without the corresponding read-only passphrase)
  • Wrapped DEKs and signing keys for each write key (useless without the corresponding write passphrase)
  • Signing public key (Ed25519) for cryptographic write enforcement (stored unencrypted for signature verification)

That's it. No names. No emails. No accounts. Server logs may contain IP addresses for security purposes, but your vault's activity history — including which IP addresses accessed your vault — is stored encrypted within your vault, so only you can see it.

A Guide, Not a Replacement

This vault is designed to be a roadmap for your loved ones — a way to help them find what they need during a difficult time. It should point them to where your important documents are stored, not replace those documents.

Original documents like wills, deeds, titles, powers of attorney, and insurance policies should always be kept in secure physical locations: a fireproof safe, a safe deposit box, or with your attorney. Use this vault to tell your family where to find them.

Best practice: For sensitive items like account numbers or access codes, consider storing hints or locations rather than the actual values. For example: "Bank account PIN is in the small blue notebook in my desk drawer" rather than the PIN itself.

Remember: This level of privacy means you are solely responsible for your passphrase. Write it down. Store it safely. Share it only with people you trust completely.

Threat Model: What We Protect Against

No security system protects against everything. Here's an honest assessment of what this vault can and cannot protect you from:

What we protect against:
  • Server database compromise: If an attacker gets our database, they only get encrypted blobs. Without your passphrase, your data is unreadable.
  • Honest-but-curious operator: We designed the system so we cannot read your data, even if we wanted to. We never see your passphrase or plaintext.
  • Unauthorized writers: Cryptographic signatures ensure only people with the signing key can modify your vault.
  • Replay attacks: Monotonic versioning and timestamp checks prevent attackers from replaying old updates.
  • Brute-force attacks: Argon2id makes passphrase guessing extremely expensive, and rate limiting blocks automated attacks.
What we cannot fully protect against:
  • Compromised client code: This is a web app. If our servers are compromised and serve malicious JavaScript, that code could potentially capture your passphrase before encryption. We mitigate this with strict CSP headers, no third-party scripts, and a verifiable release manifest, but this risk cannot be eliminated for web apps.
  • Compromised user device: If your computer has malware, keyloggers, or browser extensions that capture your input, encryption cannot help you.
  • Sharing your passphrase: If you share your passphrase with someone, or if it's intercepted, anyone with that passphrase can access your vault.
  • Legal compulsion with client modification: If we were legally compelled to modify our code to capture passphrases, users would be at risk until they verify the release manifest.

Important context: The limitation about client code applies to all web-based encryption apps. Native desktop apps with reproducible builds offer stronger guarantees, but we chose the web for accessibility. We compensate with release manifests, strict CSP, and full transparency about these tradeoffs.

Build Transparency & Verification

To help you verify that the code running in your browser hasn't been tampered with, we publish a release manifest at every deployment. This manifest contains SHA-256 hashes of every JavaScript and CSS file we ship.

What's in the Manifest

The release manifest is available at /.well-known/wsh-release.json and contains:

  • Version: A unique identifier for this build (date + build ID)
  • Build timestamp: When this version was compiled
  • Asset hashes: SHA-256 hash of every JS and CSS file, keyed by path

A human-readable version is also available at /.well-known/release.txt

How to Verify

To verify that the code you're running matches the published manifest:

  1. Open browser DevTools (F12 or right-click → Inspect)
  2. Go to the Network tab and reload the page
  3. Filter by JS or CSS to see the loaded assets
  4. Compare the file paths against those in the manifest — they should match
  5. For deeper verification: Copy a file's content, compute its SHA-256 hash, and compare against the manifest. On macOS/Linux: echo -n "file contents" | shasum -a 256 | base64

Current build version:

Limitations

While this doesn't prevent a compromised server from serving both altered code and an altered manifest, it creates a public record with several benefits:

  • Anyone monitoring our releases can detect unauthorized changes
  • The manifest can be compared against our source code repository
  • Targeted attacks (serving different code to specific users) become detectable when users compare manifests
  • It creates accountability — we cannot silently modify deployed code

For maximum security: Security researchers, journalists, or users with elevated threat models should verify the manifest against our public source code, use browser extensions that monitor script integrity, or access the site through Tor to detect targeted attacks.

What We Log

Transparency about logging is part of security. Here's exactly what our servers record:

DataLogged?Purpose
IP addressesTemporarilyRate limiting, abuse prevention
TimestampsYesOperational monitoring
Request types (GET/PUT)YesDebugging, capacity planning
Vault IDsNo
PassphrasesNo
Passphrase hashesNo
Vault contentsNo

IP addresses are used only for rate limiting and are not retained long-term. We do not correlate IPs with vault access patterns. Your vault's internal activity log (which records access history) is stored encrypted within your vault, not in our server logs.

Additional security measures we employ:

  • Content Security Policy (CSP): A strict CSP restricts scripts, styles, connections, and embeds to same-origin only. Third-party scripts are blocked entirely, and features like iframes, plugins, and form submissions to external origins are disallowed.
  • Hardened HTTP headers: Every response includes HSTS with preload, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy no-referrer, Cross-Origin-Opener-Policy same-origin, Cross-Origin-Resource-Policy same-origin, and a Permissions-Policy that disables camera, microphone, geolocation, payment, USB, Bluetooth, and other unnecessary browser features.
  • Request size enforcement: The middleware rejects any API request body larger than 5 MB, requires a Content-Length header on all write requests to prevent chunked-encoding bypass, and validates individual field sizes and total body size before processing.
  • KDF parameter validation: Server-side validation ensures Argon2id parameters (opslimit, memlimit) stay within safe bounds, preventing denial-of-service through extreme key derivation settings.
  • Cryptographic write enforcement: Vault updates require an Ed25519 digital signature over the ciphertext, nonce, wrapped key, KDF salt, algorithm identifier, and version number. The server verifies this signature and checks that the signing timestamp is within a five-minute window to prevent replay.
  • Optimistic locking and version control: Every vault save must increment the version by exactly one. The check runs inside a Redis WATCH transaction to prevent concurrent writers from overwriting each other or rolling back to an earlier version.
  • Timing normalization: Authentication and lookup endpoints pad their response time to a fixed minimum, and always execute all credential lookups in parallel, so that response latency does not reveal whether a passphrase matched an owner, read-only key, write key, or nothing.
  • Multi-layer rate limiting: Limits are applied per IP, per vault, and per hash prefix across creation, access, update, delete, and authentication endpoints to slow automated attacks.
  • Timing-safe comparisons: Passphrase hash verification uses constant-time comparison to prevent timing side-channels.
  • API response cache control: All API responses include Cache-Control: no-store to prevent browsers or proxies from caching encrypted vault data.
  • Vault ID hashing in logs: Vault identifiers are never logged directly. Instead, a truncated SHA-256 hash is recorded, allowing log correlation without exposing the actual vault ID.
  • No third-party scripts or tracking: The application loads zero third-party JavaScript, uses no analytics, sets no tracking cookies, and does not include any external fonts, images, or resources.

Prefer to Keep Everything Offline?

We understand that not everyone is comfortable storing sensitive information online — even with strong encryption. That's a completely valid choice.

If you'd rather keep your information entirely offline, we offer a free printable life organizer that you can fill out in your browser and print. Nothing is saved or transmitted — your data stays completely local, and when you close the page, it's gone.

The printable organizer is perfect if you:

  • Prefer physical documents you can lock in a safe
  • Don't want any data stored on the internet
  • Want something your family can access without technology
  • Simply trust paper more than servers

No judgment here — we built both options because different people have different comfort levels with technology and risk.

Data Export & Manual Decryption

We believe your data belongs to you — completely. From your vault, you can export your data in two formats:

  • Decrypted JSON: Your complete vault data in a human-readable format, useful for backups or migrating to another system.
  • Encrypted Bundle: The raw encrypted data along with all the parameters needed to decrypt it yourself using standard open-source cryptographic tools.

The encrypted bundle export ensures you can always recover your data — even if our service becomes unavailable. Combined with your passphrase, you can decrypt your vault using Node.js, Python, or any tool that supports libsodium/NaCl.

Full transparency: We provide a complete technical guide with working code examples for manually decrypting your vault. No hidden formats, no proprietary algorithms — just standard cryptography you can verify yourself.