Password managers are the single highest-ROI security upgrade a person can make. But "use a password manager" is not a complete sentence — because the threat model of a cloud-synced vault and a local-first browser extension are fundamentally different, and that difference matters.
What a password manager is actually protecting you from
Before evaluating any password manager, you need to be clear about which threats you're trying to address:
- Credential reuse — the root cause of most account takeovers. A unique password per site makes a breach at site A useless at site B.
- Phishing — autofill only triggers on the exact registered domain. A credential manager that autofills on
paypal-secure.xyzis not a security tool. - Weak passwords — humans are bad at entropy. A generator with 20+ character random strings fixes this by default.
- Server-side breach — if the password manager's own servers are breached, what's exposed? This is where architecture matters enormously.
Most commercial managers solve the first three well. The fourth is where local-first architecture has a structural advantage.
The cloud sync attack surface
When your vault is synced to a cloud server, the threat model expands. Even with end-to-end encryption, you're trusting:
- The vendor's key derivation implementation is correct
- The client never sends plaintext or weakly-derived keys
- The vendor's infrastructure isn't compromised at the application layer (supply chain, insider threat)
- The vendor doesn't change their encryption scheme in a future update
- The vendor remains solvent and doesn't sunset the product
LastPass (2022) is the instructive case study. The breach exposed encrypted vault blobs, but because many accounts used weak master passwords or the old default of 1–5k PBKDF2 iterations, attackers were able to crack vaults offline at scale. The vault blobs were at rest on a server — which meant a single infrastructure breach gave attackers unlimited offline cracking time.
Local-first: smaller attack surface, different trade-offs
A local-first vault never leaves your device in a form a server can decrypt. The encrypted blob lives in your browser's storage. The key is derived from your master password and exists only in memory during an unlocked session.
The trade-offs are real:
- No cross-device sync — you can't access your vault from your phone unless you export and re-import, or use a separate sync mechanism you control
- No backup by default — if you lose the device and haven't exported, your vault is gone
- No breach notification — the vendor can't scan your credentials against breach databases on your behalf without seeing the credentials
But what you gain is equally concrete: there is no server-side infrastructure to breach. No cloud vendor to trust. No export of your encrypted blob to an attacker's offline cracking rig.
How FoilVault implements local-first encryption
FoilVault stores everything in chrome.storage.local — the browser's sandboxed local storage for extensions, not synced to Google accounts. The encryption chain is:
- Key derivation — PBKDF2-SHA256, 600,000 iterations, random 128-bit salt. This is the 2024 OWASP-recommended iteration count, making offline brute-force attacks take years per guess at consumer GPU speeds.
- Encryption — AES-GCM 256-bit with a random 96-bit IV per encryption operation. GCM provides both confidentiality and integrity — any tampered ciphertext fails to decrypt.
- Master password — never stored, not even hashed. The vault decrypts or it doesn't. Wrong password = failed GCM tag verification.
The vault blob stored in chrome.storage.local looks like: { salt, iv, ciphertext } — all base64, none decryptable without the master password.
TOTP and breach detection in a local-first model
Two features that seem to require a server actually don't:
TOTP (authenticator codes) — RFC 6238 is a pure algorithm. TOTP = HOTP(key, floor(unix_time / 30)) with HMAC-SHA1. FoilVault computes this entirely client-side using SubtleCrypto. No server, no network request — the 6-digit code is generated in the browser on click.
Breach detection — the k-anonymity model used by Have I Been Pwned means you only send the first 5 characters of the SHA-1 hash of your password to the API. The API returns all hashes starting with those 5 chars; your browser checks the list locally. HIBP never sees your actual password, and FoilVault implements this check on demand from the credential editor.
What FoilVault doesn't do (and why)
FoilVault deliberately omits certain features that would compromise the local-first model:
- No cloud sync — export as encrypted JSON or plaintext CSV and manage sync yourself
- No account recovery — forget your master password and your data is gone. This is a feature, not a bug: recovery means a server knows something that can unlock your vault
- No sharing — shared vaults require a server to mediate key exchange
- No browser history of visited sites — autofill matches against the current tab's domain; no logging
Who this model is right for
Local-first is the right threat model if you:
- Trust your device security more than third-party cloud infrastructure
- Primarily work from one machine or are comfortable managing manual exports for multi-device use
- Have a high-value target profile — journalist, researcher, executive — where the risk of cloud vendor breach outweighs the convenience
- Want to understand exactly what code runs against your credentials (FoilVault is AGPL, fully auditable)
If you need seamless cross-device sync, a good commercial manager with a strong E2EE implementation (Bitwarden, 1Password) is the pragmatic choice. FoilVault ships with a Bitwarden import format precisely because these tools solve different parts of the problem and should be able to coexist.
The intersection with FoilGuard
A password manager without phishing protection is incomplete. You can have a unique, 32-character random password for your bank — and still hand it to an attacker on bankofamerica-secure.com if your autofill fires on the wrong domain.
FoilGuard's domain scoring runs synchronously before a page loads. If a site scores above the configured threshold, navigation is intercepted before autofill can trigger. The combination — FoilVault for credential storage, FoilGuard for domain verification — closes the loop that either tool leaves open on its own.
FoilVault is AGPL licensed on GitHub. Load it from dist/ after running npm run build.