Security

Don't trust. Check.

This page states what Keepsake protects against, what it doesn't, and how to verify our claims yourself. Honesty is the point.

Architecture in one paragraph

Keepsake is local-first and zero-knowledge by construction. Your documents are encrypted with AES-256-GCM on your device, under keys derived only from things you hold (your password, recovery phrase, or your device's hardware keystore). Encrypted data is stored on your device and — if you enable sync — in your own Google Drive or OneDrive. Keepsake the company operates no document servers. We cannot read, lose, leak, or be compelled to hand over your documents, because we never possess them in any form.

What we protect, and from whom

A security page that lists only wins is marketing. Here is the full table, including the ❌ rows.

ThreatProtected?How
Stolen or lost laptop/phoneYesEverything AES-256-GCM encrypted at rest; keys derived via Argon2id from your password; auto-lock wipes keys from memory
Cloud provider reading your synced vaultYesGoogle/Microsoft store only ciphertext blobs; keys never leave your devices
Keepsake (us) reading your dataYesStructurally impossible — no servers hold your data or keys
A data breach at KeepsakeYesOur website database contains at most your email and license record — never documents or keys
Ciphertext tampering (malicious cloud, MITM)YesGCM authentication plus AAD binding; modified files fail decryption loudly
Replaying an old vault stateYes (local)Index generation counter — a device refuses to load older state than it has seen
Secure Send link interceptionYesEncrypted client-side; the key travels in the URL fragment, which browsers never send to servers; optional PIN; burn-after-read
Audit-log falsificationYesHash-chained audit records, verifiable in Settings
A weak or guessed passwordPartialArgon2id (memory-hard) makes offline guessing expensive; a strength meter nudges you — but we cannot stop you choosing "123456"
Malware on your unlocked deviceNoNo app can defend a compromised OS with the vault open. Keys are held only while unlocked and zeroed on lock, which limits the window
Forgetting your password AND losing the Recovery KitNoZero-knowledge means exactly that: nobody — including us — can reset it. Treat the Recovery Kit like cash
Coerced unlock ("rubber-hose")NoOut of scope (Travel Mode limits what a device carries across borders)

Cryptography

  • Encryption: AES-256-GCM, random 96-bit nonce per file, AAD binding ciphertext to document identity. No unauthenticated modes anywhere.
  • Key derivation: Argon2id (64 MiB / 3 iterations / 4 lanes on desktop, tuned per platform); parameters stored openly in the vault manifest.
  • Envelope keys: a random 256-bit Master Key encrypts data; your password, recovery phrase or biometric key only wrap it. Password changes never re-encrypt your documents.
  • Recovery: a 24-word BIP-39 phrase (printable kit with QR) wraps the same Master Key.
  • Biometrics: Windows Hello / Android Keystore hold a hardware-backed wrapping key; biometric data never touches Keepsake.
  • Passkeys and security keys: in the web app and in the Windows app, WebAuthn's PRF extension makes the authenticator produce 32 bytes that only that credential can produce; HKDF over them — with the vault id in the info string, so one key can hold slots on several vaults without sharing a secret — is the wrapping key. A passkey therefore opens the encryption, not a login: no server is asked whether you may proceed. A key a device holds is never the only way in — enrolling is refused until a password or recovery phrase exists, and removing the last way in is refused outright. The Windows app asks the key for the same function directly over CTAP2, where it is called hmac-secret, and reproduces the hash a browser applies to the salt before passing it on — which is what makes one physical key open the same vault on both surfaces rather than two keys that merely look alike (how it works). The Android app does not take a security key.
  • Licenses: Ed25519-signed, verified offline; the license system knows your email, never your data.
  • Boring on purpose: AES-GCM, Argon2id, HKDF, SHA-256, Ed25519, BIP-39 — no home-made crypto.

How to verify us

  1. The format is public. The vault format documents every byte — an independent tool can decrypt your vault with your password alone. Read the specs: Vault Format v2 · Security Model · Secure Send protocol.
  2. Network transparency. Run the apps behind a proxy: you'll see traffic only to your chosen cloud provider. License checks are offline; there is no telemetry endpoint to find.
  3. Download integrity, without trusting this website. Every release is published with a manifest of SHA-256 checksums, signed with the Ed25519 release key below — a key that never touches this web server. A checksum printed on a page the attacker also controls proves nothing, so the signature is the part that matters. Check any download with Keepsake.exe --verify <file> from a copy you already had installed, or drop it on the verify page. Write the key down once and you can verify every future release by hand, forever, even if this site is gone or lying:
    3b0e3f9d86279b9aac72bbb497996f5b053f95c62422ab75f00c72598320af76
    The update channel uses the same key: the desktop app verifies the signed feed before applying anything, so nobody who controls this server can push code to installed copies.
  4. Reproducible builds. A signature answers “did this file come from Keepsake”. It does not answer “is this file what that source compiles to” — and for a product whose whole claim is that it cannot read your documents, the second question is the one worth asking. Our builds are now deterministic: the same commit, built with the SDK global.json pins, produces byte-identical binaries on any machine and in any directory. pwsh tools/reproduce.ps1 is the check — it builds the same commit twice, in two differently named directories, and compares SHA-256 over every file. Two things follow that you can see without our source: the binaries carry no path from our machines (no developer’s home directory inside a file you run), and each release can publish the hash manifest that build produced. Honestly: this applies from the next release onwards. Builds published before 7 September 2026 were made without it, and their binaries do contain build paths. And while the source is not public, this is a command we run and you check the output of — the day the source is available it becomes a command you run.
  5. Authenticated encryption, demonstrated rather than asserted. Every vault in this category prints “authenticated encryption” on its website and almost none of them show you what it buys. Run the experiment: pwsh tools/compare/tamper.ps1 stores the same specimen document twice — once as a Keepsake blob (AES-256-GCM), once in an XTS-AES container of the kind VeraCrypt, BitLocker and LUKS create — then flips one bit at the same place in each and reads both back. Keepsake refuses the document by name and returns nothing at all. The container returns the document, sixteen bytes different, with no error, no warning and no way it could have known. -SelfTest asserts both halves, so if our format ever stopped refusing altered bytes the check would fail rather than the page quietly go on saying this.
    Said fairly, because the transcript says it too: this is about detection and nothing else. XTS is not broken and VeraCrypt is not insecure — XTS is length-preserving by design, which is exactly why it has nowhere to put an authentication tag, and that is a trade disk encryption makes on purpose. An attacker who can write to either store still cannot read it and cannot choose what the garbled block becomes. What differs is what happens when nothing catches it.
    The transcript, as the command printed it (raw)
    Keepsake — one bit, flipped in a stored document
    =================================================
    
    Run:        2026-09-13 11:56:46Z
    Command:    dotnet run --project tools/compare/TamperDemo
    Document:   144 bytes of specimen passport data
    SHA-256:    c03cb2844e0a04117b90a1275eaf458f22dbba25bce5f1a0ffaa6fb3c3037965
    
    The same document is stored twice: once the way Keepsake stores it, and once the
    way a disk-encryption container stores it. Then one bit is flipped in each, at the
    same offset within the encrypted bytes, and each is read back.
    
    1. Keepsake (KVF2 blob: AES-256-GCM, docs/VAULT_FORMAT_V2.md §6)
       ---------------------------------------------------------------
       stored              178 bytes (18-byte header + ciphertext + 16-byte tag)
       read back clean     byte for byte identical
       flipped             1 bit at offset 42, inside the ciphertext
       read back tampered  refused
         exception         VaultTamperException
         message           This file did not pass its authentication check. It is not the file that was stored, or it is being opened with the wrong key. Nothing has been returned from it.
         bytes returned    none
    
    2. A container (XTS-AES-256, the mode VeraCrypt, BitLocker and LUKS use)
       ---------------------------------------------------------------------
       stored              144 bytes — exactly the size of the document,
                           which is the point of XTS and the reason it has no room for a tag
       read back clean     byte for byte identical
       flipped             1 bit at offset 24, the same place in the document
       read back tampered  SUCCEEDED — no error, no warning, no refusal
         bytes returned    144
         bytes changed     16 of 144 (one 16-byte block, garbled)
         rest of document  intact and readable
    
       What the reader gets back, first line onward:
         | PASSPORT (SPECIM···7=m··'··C}D··UM
         | Given names: SULTANA
         | Passport no: 533401829
         | Date of expiry: 14 AUG 2031
         | Issuing authority: HMPO
         | 
    
    What this does and does not show
    --------------------------------
    It shows detection, and only detection. An attacker who can write to either store
    still cannot read it, and cannot choose what the garbled block becomes — XTS gives
    them sixteen random-looking bytes, not a sentence of their choosing. On a mounted
    filesystem, a corrupted block is often caught by the filesystem instead.
    
    What differs is what happens when nothing catches it. Keepsake refuses the document
    and says why. The container hands back a document that is sixteen bytes different
    from the one that was put in, and says nothing, because there is nothing in the
    format that could have known. Neither behaviour is a bug: XTS is length-preserving
    on purpose, and a tag will not fit in a design that must not grow. It is a trade,
    and a vault for documents you will be asked to prove is on the other side of it.
    
    VeraCrypt is not insecure, and nothing here suggests it is. It encrypts disks, and
    this is the property disk encryption gives up to be able to encrypt disks.
    
  6. Code signing, honestly. Windows installers are not Authenticode-signed yet, so Windows shows an "unrecognised app" warning on first run. We would rather tell you that than have you wonder. The signature scheme above is what protects you in the meantime, and it protects the update channel — which the certificate would not.
  7. Survivability. If Keepsake disappears tomorrow, the apps keep working, your data stays in your cloud, and the published spec is enough to recover everything.

What this website knows about you

At most: an email address you volunteered, upgrade requests, and Secure Send ciphertext that auto-deletes. No third-party trackers, no ad-tech, no fingerprinting, no cookies on public pages. Details in the privacy policy.

Known past weaknesses (public changelog)

Installs before Vault Format v2 used AES-256-CBC without authentication and direct password-derived file keys. v2 replaced this with authenticated GCM and envelope keys; vaults migrate automatically on first unlock after update. We document this because pretending past versions were perfect is how vendors earn distrust.

Reporting security issues

Email hello@securekeepsake.com. No bug-bounty budget yet — but credited acknowledgements, fast fixes and honest disclosure notes are guaranteed. Please practice coordinated disclosure.

The terms are written down rather than implied: scope, timelines and a safe-harbour commitment are in the vulnerability disclosure policy, and the machine-readable contact is at /.well-known/security.txt (RFC 9116).

Every claim on this page is indexed in the claim ledger, with the command that reproduces it — and the ledger lists what Keepsake does not have in the same table. It is generated, so a number here that stopped matching the artefact it came from would fail the build rather than survive on the page.

What we have not done: commissioned an independent security audit. What stands behind the claims above is a published format you can decrypt a vault from without us, a signed release channel, a reproducible build, and an audit that counts the checks which actually ran rather than the ones we remember writing (pwsh tools/audit/audit.ps1 — the current report is indexed in the ledger), and this page — evidence you can check, not evidence a third party has checked. The distinction is real and we score ourselves down for it on the criteria page.

Last verified — by pwsh tools/audit/audit.ps1. Every claim on this site is listed, with its evidence, in the claim ledger.