VaultTabs
PROTOTYPESync open browser tabs across devices. Snapshots are encrypted in the browser, but it is not zero-knowledge.
Personal project · Feb–Mar 2026 · 57 commits
THE PROBLEM
Tab-sync tools usually upload your URLs to a server in plaintext, and the built-in browser sync is tied to one vendor.
HOW IT WORKS
- A browser extension (WXT, Chrome Manifest V3) captures open http(s) tabs, skips incognito tabs, and encrypts the list with a random AES-256-GCM master key before uploading.
- The master key is wrapped with a key derived from the account password (PBKDF2, 100,000 iterations) and optionally with a one-time recovery code. A Next.js PWA and other extensions unwrap it locally to view snapshots and send a tab to another device.
- A Fastify and PostgreSQL backend stores ciphertext and the wrapped keys.
THE PIPELINE
- ExtensionCaptures open http(s) tabs and skips incognito tabs.
- Encrypt in the browserRandom AES-256-GCM master key, fresh IV per snapshot.
- Fastify and PostgreSQLStore ciphertext and the wrapped keys.
- PWA or another extensionUnwraps the master key with a key derived from the password (PBKDF2) and decrypts locally.
ENGINEERING EVIDENCE
- Snapshots are AES-256-GCM encrypted client-side with a fresh random 96-bit IV each, so a stolen database contains no readable tab data. A script checks this against the database. crypto.ts ↗
- A Sep 2026 review fixed real defects: restore requests could be read or completed by any logged-in user, JWTs never expired, CORS was open outside production, and the docker-compose healthchecks were malformed so the backend never started. restore.service.ts ↗
WHAT ISN'T DONE
- Not zero-knowledge. The account password is sent to the server (over TLS) at sign-up and login, and the same password protects the master key, so a server operator who captures passwords can decrypt every snapshot. Fixing it needs an authentication redesign, such as a separate auth secret or OPAQUE.
- The server sees your email, device names, timestamps, snapshot sizes and restore target URLs.
- The first README and the app copy claimed zero-knowledge. They were corrected in Sep 2026.
- There is one integration test file. The Docker setup and the fixes above were type-checked and built but not run end to end.
NEXT STEPS
Each one comes from a gap listed above. It says what fixing the gap would take; it is not a promise.
- Stop sending the account password to the server, by using a separate authentication secret or OPAQUE.
- Use a stronger key-derivation function than PBKDF2 with 100,000 iterations, and encrypt restore target URLs.
- Run the Docker setup end to end against a real database.
STACK
- TypeScript
- WXT
- Next.js
- Fastify
- PostgreSQL
- WebCrypto
- Docker