Este documento está disponível apenas em inglês. A versão inglesa é a que tem validade legal.
This document describes exactly how VaultPassword protects your data: which algorithms are used, which secrets exist and where they live, what our servers can and cannot read, and — just as importantly — what this design does not protect you against.
It is written to be verifiable rather than reassuring. Where the current implementation falls short of the design, that is stated plainly in Known limitations.
1. Two different secrets
Most confusion about password managers comes from collapsing two separate things into one. VaultPassword keeps them strictly apart:
- Your account password. This only gets you in. It is sent to our server on sign-in, and stored there as a bcrypt hash. It never touches your vault contents.
- Your master key. This is what actually encrypts and decrypts your vault. It is generated on your device and is the secret that matters.
The consequence is the point of the whole design: somebody who steals our database, or who compels us to hand it over, gets encrypted blobs and no way to open them. Breaking the account password gets an attacker into an account whose contents they still cannot read.
2. The master key
Your master key is 32 bytes (256 bits) drawn from the operating
system's cryptographically secure random generator —
crypto.getRandomValues in the browser, the system CSPRNG on
Android — and shown to you encoded in base64.
It is not a password you choose, and that is deliberate. A human-chosen passphrase is guessable: an attacker with the encrypted vault can run a dictionary against it offline, at billions of attempts per second, which is why other products need deliberately slow key derivation (PBKDF2 with hundreds of thousands of iterations, or Argon2) to make each guess expensive.
There is no dictionary for 256 random bits. Guessing it is not a matter of better hardware; it is not possible. This is why VaultPassword derives with HKDF-SHA256 rather than a slow KDF: HKDF is the correct primitive for deriving keys from a secret that already has full entropy, and slowing it down would buy nothing.
The trade-off is honest and it is yours to accept: you have to store that key somewhere. If you lose it, your vault is unrecoverable — see section 7.
3. Proving you know the key, without sending it
Your apps need to check that the master key you typed is the right one. The naive way — send it to the server and compare — would defeat the entire design.
Instead, your device derives two independent values from the master key:
- The encryption key, via HKDF-SHA256. This never leaves your device.
-
The authentication verifier:
SHA-256("vaultpassword-auth-v1|" + master key). This is the only derived value that is transmitted. The server stores a bcrypt hash of it.
The literal prefix is domain separation: it guarantees the verifier can never coincide with any other value derived from the same key, now or in any future feature.
So an attacker who steals the database and breaks bcrypt obtains something that lets them authenticate — and still cannot decrypt a single stored password, because the verifier is a one-way function of the key and not the key itself.
4. How an item is encrypted
Each vault item is sealed into a single authenticated blob:
- Cipher: AES-256-GCM.
-
Key: HKDF-SHA256 over the master key, with salt
vaultpassword-item-v2and infoaes-256-gcm, producing 32 bytes. - Nonce: 96 bits, freshly random for every single encryption. It is stored alongside the ciphertext; a nonce is not a secret, it only has to be unique.
- Plaintext: a JSON object containing everything — the item name and, depending on its type, the site, username, email, password and TOTP secret of a login; the number, cardholder, expiry, security code and PIN of a card; or the name, document number, date of birth, phone and address of an identity. Notes and custom fields too. Nothing about an item is stored outside that object — including what kind of item it is: the server cannot tell a login from a card.
The stored value looks like v2.<nonce>.<ciphertext+tag>.
The format is identified by that explicit prefix and by a
format_version column, never by guessing at the content.
Why GCM specifically
AES-GCM is authenticated encryption: it carries a tag that makes tampering detectable. If a single byte of your data is altered — by a malfunctioning disk, a bug, or a hostile server — decryption fails loudly.
Unauthenticated encryption does not fail. It returns garbage, or an empty string, and an application that treats an empty string as "this field was blank" will happily overwrite good data with nothing. Silent corruption is worse than an error, because nobody notices it until the backups have rotated.
Verify before overwrite
Whenever an item is re-encrypted, the new blob is decrypted again and compared against the original before anything is written. If they differ, the write is abandoned and the original is left untouched. A snapshot of the previous state is also retained server-side as a second line of defence.
5. What our servers can see
For an item in the current format, the server holds an opaque blob and the following, which it genuinely needs in order to function:
- Your account: username, email address, and when it was created.
- Which items belong to you, and how many.
- When each item was created and last modified.
- Whether an item is marked as a favourite.
-
Your linked devices: a client-generated identifier, a display name and a
platform (
android,extension), so that device limits can be enforced and you can unlink a lost phone. - Subscription status and billing history.
It cannot see: any password, any username or email stored inside an item, any site or URL, any note, any custom field, any TOTP secret, the name you gave an item, or your master key.
Metadata is not nothing, and we are not going to pretend otherwise: knowing that you have 140 items and that one of them changed this morning is information. But it is information about the shape of your vault, not its contents.
6. Where decryption happens
Decryption happens only inside the app or the extension, in the process that holds the master key.
This matters most for Android autofill. When another app or a browser asks VaultPassword to fill a login, the system briefly connects to a background service of ours. That service never decrypts anything — it cannot, it does not have the key. It returns placeholder entries; when you tap one, VaultPassword itself opens, decrypts the item in its own process, and hands back only the two fields being filled.
The alternative — decrypting the vault in the background service so entries appear pre-filled — is more convenient and puts your plaintext credentials in a process that other applications can trigger. We did not do that.
The same rule governs search. Because the server cannot read item names or URLs, matching a site to your saved logins is done on your device, against the decrypted vault.
7. There is no recovery
If you lose your master key, your vault is gone. Not "difficult to recover" — gone. We cannot reset it, we cannot recover it, and no support request can change that, because we never had it.
This is not a missing feature. Any mechanism that let us restore your vault would, by definition, be a mechanism by which we could read it — and would be available to anyone who compromised or compelled us. A recovery option and a zero-knowledge design cannot both be true.
Store your master key somewhere durable and offline before you rely on VaultPassword for anything important. Resetting your account password does not affect your master key; they are independent.
8. Account security
- Account passwords are stored as bcrypt hashes, never in plaintext and never reversibly.
- Two-factor authentication (TOTP, RFC 6238) can be enabled on your account. It protects sign-in; it does not affect vault encryption.
-
Access tokens expire after 24 hours. On Android they are
held in the system keystore (
expo-secure-store); in the browser, in extension storage, which is not reachable from web pages. - Google Sign-In replaces only the account password. Google never sees your master key, and signing in with Google does not give us any additional ability to read your vault. You still set and keep a master key of your own.
- Transport is HTTPS/TLS for every request. Credentials are never placed in URLs or query strings, so they cannot end up in server access logs.
9. Analytics
We collect anonymous usage statistics through a self-hosted analytics instance. What is sent is limited to which screens are opened and which features are used, plus platform and application version.
What is never sent, by design and not by policy: vault contents, item names, site URLs or domains, usernames, email addresses, account identifiers, or device identifiers. Analytics can be turned off in settings.
10. What this does not protect you from
No encryption design protects against everything. These are the cases where VaultPassword will not save you:
- A compromised device. Malware with control of your phone or browser can read your master key while you use it. Client-side encryption assumes the client is trustworthy; if it is not, nothing below it helps.
- A malicious update from us. You run our code. A deliberately backdoored release could transmit your key. This is structural and applies to every password manager that ships software; what limits it is reproducibility and scrutiny, not cryptography.
- Phishing. If you are convinced to type your master key into a page that is not ours, the design offers no protection.
- Losing your master key. See section 7.
- Traffic and metadata analysis. We can see when you sync and roughly how large your vault is.
11. Known limitations
This section exists because a whitepaper that only describes the intended design is marketing. These are the gaps between the design above and what is deployed today.
- Older items are still in the previous format. VaultPassword predates the design described here, and vaults created before it are being migrated item by item. In the previous format the item name was stored in plaintext on the server, the other fields were encrypted with a server-held key in addition to yours, and the cipher was unauthenticated. Until an item is migrated, section 5 does not fully apply to it. Migration is performed on your device with your master key — we cannot do it for you — and preserves a rollback snapshot.
- The master key transition is not finished. The verifier described in section 3 is the current mechanism, but accounts created under the older scheme are still being moved across, and during that window such an account's master key is transmitted once, on validation, in order to complete the move. Accounts already migrated never transmit it.
-
No independent audit. The cryptography here uses standard,
well-reviewed primitives and widely used implementations
(
@noble/ciphers,@noble/hashes), but this codebase has not been reviewed by an external security firm. We are not going to claim otherwise. - Sharing is read-only for recipients, and revocation has a limit. Only the owner of a shared item can edit it. Removing someone re-encrypts the item under a fresh key so they stop seeing future changes — but nothing can take back what they already read or copied. No system can, and we would rather say so than imply otherwise. See section 11.
- iOS autofill is not available. The Android integration described in section 6 has no iOS counterpart yet.
12. Sharing
Sharing an item never involves handing over your master key, and never lets our servers read what you shared. It works in three layers:
- Every account that shares or receives has an X25519 key pair. The private half is stored on our servers encrypted with your master key; the public half is stored in the clear, because a public key is not a secret.
- Each shared item is encrypted with its own random content key, not derived from anybody's master key.
- That content key is wrapped once per recipient, using the X25519 shared secret between sender and recipient, run through HKDF-SHA256. Both public keys are bound into the derivation, so a wrapped key made by A for B cannot be replayed in the other direction or attributed to someone else.
The honest limit. You receive the recipient's public key from us. A compromised or coerced server could hand you a different one and read what you share. Cryptography cannot close that hole on its own — which is why both apps display a six-group fingerprint of every key. Comparing it with the other person over a different channel, once, is what closes it.
Losing your master key also loses access to shared items, since it is what protects your private key. The same rule as section 7, for the same reason.
13. Emergency access
You can name someone as an emergency contact. If they request access and you do not deny it within a waiting period you choose, they get in.
This is built on the same envelope as sharing: your master key, wrapped with their public key. We never see it. But the design has two properties you should understand before you use it, and we would rather you read them here than discover them later.
- It hands over the entire vault. There is no cryptographic way to grant "some passwords" or "read-only": whoever holds the master key holds everything. Removing the contact afterwards does not take the key back — only changing your master key does, which re-encrypts the vault.
- The waiting period is enforced by our servers, not by cryptography. The envelope exists from the moment you name the contact; what stops them opening it early is that we do not hand it over. This is the one place in this document where a dishonest server could cheat, and we are not going to bury it in a footnote.
If neither of those is acceptable for your threat model, do not use the feature. It exists because "my family cannot get to anything if I die" is a real problem, and an honest imperfect answer beats no answer.
14. Reporting a vulnerability
If you find a security problem, please report it privately to [email protected] before disclosing it publicly, and give us a reasonable window to fix it.
We would rather receive an uncomfortable report than not receive it. If you believe something on this page is inaccurate, that is also worth an email.