pswrds
Open pswrds

How pswrds protects your passwords

Security design · last updated 6 October 2026

This page describes exactly how pswrds encrypts and stores your data, what it protects against and what it doesn't. It's written for technical readers, security researchers and auditors. The full source code is on GitHub under the AGPL-3.0 licence. If you only want the short version, read the questions and answers.

01Design goals

02What the server stores

ItemWhat it is
Vault IDSHA-256 of "pswrds-account:" + username. The username is lowercased and Unicode-normalized (NFC) first, and is never sent.
Salt and iteration count16 random bytes per vault, and the PBKDF2 iteration count (600,000).
8 slotsEach exactly 65,564 bytes of encrypted data. Unused slots are random bytes of the same size.
Slot versionsA random number per slot that changes on every save, so two devices can't silently overwrite each other's changes.
Write-token hashSHA-256 of the vault's write token (see section 05).
Creation time, paid flagWhen the vault was created, and whether it has unlimited records.

The server never receives a passphrase, a key, a record, a wallet name or the number of wallets in a vault.

03Keys and encryption

  1. Each passphrase is turned into a 256-bit key with PBKDF2-HMAC-SHA256, 600,000 iterations, using the vault's salt. Every passphrase of a vault has its own key.
  2. A slot holds a JSON document padded with random bytes to exactly 65,536 bytes: a 4-byte length, the JSON, then padding. Because every slot has the same size, its size reveals nothing about how much it holds.
  3. The padded document is encrypted with AES-256-GCM using a fresh random 96-bit nonce on every save. The additional authenticated data is "pswrds:" + vault ID + ":" + slot number, so a slot can't be moved to another position or another vault.
  4. To unlock, the app derives the key and tries it on all 8 slots. It always tries all of them, and it runs the key derivation even when the username doesn't exist, so timing doesn't reveal which slot opened or whether a vault exists.

All cryptography uses the browser's built-in Web Crypto API. Random numbers come from crypto.getRandomValues. Generated passwords are 20 characters from a 70-character set (about 122 bits).

04Several passphrases in one vault

A vault created without an invitation code has one wallet in one slot; the other seven are random data. A vault created with an invitation code has a main slot whose document lists the other slots in use: for each one, what it does, its label and its key. That's how the main passphrase can open and manage everything, while each other passphrase opens only its own slot.

Nothing on the server distinguishes these kinds: every slot is the same size and every unused slot is indistinguishable from an encrypted one.

05Who can change a vault

When a vault is created, the app makes a random 256-bit write token and stores it inside every slot it creates. The server keeps only its SHA-256 hash and accepts a change only with the token, so only someone who can open a slot can change the vault. Changing the main passphrase issues a new token. Each save names the slot version it replaces; if another device saved in the meantime, the server refuses (HTTP 409) and the app reloads instead of overwriting.

06Fingerprint and face unlock

Optional, for one wallet per device and never for the main passphrase. The app creates a passkey and uses the WebAuthn PRF extension: after a successful fingerprint or face check, the device's authenticator returns a 32-byte secret that never leaves the device. HKDF-SHA256 turns it into an AES-256-GCM key, which encrypts that wallet's key and the username in the browser's local storage. The server isn't involved. Changing that wallet's passphrase makes the stored copy useless, and the app removes it.

07Payments and invitations

08The web app itself

09What pswrds protects against

10What it doesn't protect against

11Known limitations and planned work

12Security changes

13Reporting a vulnerability

Please write to info@pswrds.com with a description and, if possible, steps to reproduce. We'll reply within a few days, fix confirmed issues as quickly as we can, and credit you here if you'd like. Please don't access other people's vaults or disrupt the service while testing; use the demo or your own test vaults. Our security.txt has the same details.