Vaultiq
Vaultiq is a zero-knowledge password manager for Firefox, Chrome and Android. Everything is encrypted on your device before it goes anywhere. If you choose to sync, the server you run stores ciphertext and cannot read it. Item names, URLs, usernames, notes and counts are encrypted, not just the passwords.
There is no hosted service. You either keep the vault on one device, or you run the small sync server yourself.
There is no account recovery. Your master password is stored nowhere and cannot be reset by anyone, including whoever runs your server. If you lose it, the vault is gone. This is deliberate and it is the cost of the design.
Vaultiq has not been independently audited. The cryptography uses vetted RustCrypto primitives and is pinned by known-answer tests, but no third party has reviewed the code. Read What Vaultiq protects, and what it does not before trusting it with anything.
What you can do
- Store five kinds of item: logins, cards, identities, authenticator (TOTP) codes and secure notes.
- Autofill and save logins in the browser extension, and fill logins in Android apps and browsers through Android’s autofill service.
- Sync between devices through your own server, with invite-only registration and per-device revocation, or use a vault that never contacts a server.
- Unlock quickly with a PIN in the extension or a fingerprint on Android.
- Import from Chrome, Firefox, Bitwarden, LastPass and 1Password CSV, Bitwarden JSON and Proton Pass JSON, and export an encrypted backup.
Platforms
| Platform | Status |
|---|---|
| Firefox | Supported |
| Chrome | Supported (same build as Firefox) |
| Android | Supported, arm64 |
| iOS | Not available |
There are no store listings yet. Both apps are built from source; see the install pages.
Where to go next
- Choose how to use Vaultiq: with a server or without one.
- Install the extension and/or the Android app.
- If you chose a server, deploy it.
Vaultiq is free software under the GNU Affero General Public License v3.0. Source, issues and releases are on GitHub.
Choose how to use Vaultiq
You pick one of two modes when you create a vault. Read both before choosing, because the choice is hard to change later.
Local only: no server at all
The vault lives on one device. Nothing syncs and nothing listens on a port.
- Pick Use without a server when creating the vault (in the extension, the Create your vault screen; on Android, the same option on the first screen).
- Losing the device loses the vault, so keep an encrypted backup.
- In the extension, turning on Never sync this vault in Settings makes this permanent: the extension then refuses to connect to any server.
- On Android there is no way to convert a local vault into a server-backed one. The extension can upload a local vault to a new server; see Connect your devices.
Self-hosted sync
You run the Vaultiq server (Docker, PostgreSQL and Caddy). Your devices sync through it. Choose this if you want the same vault on a laptop and a phone.
- The server holds sealed items and a wrapped key. It never holds the keys that open them. It can still see how many items you have, their sizes and when you sync.
- Registration is invite-only, so a stranger who finds your domain cannot create an account.
- You need a machine with Docker and a domain name that points at it.
Follow Deploy the server first, then install the apps.
Pick a master password
Choose a long one and use it nowhere else. It is the only thing between an attacker and your vault if they get a copy of your data. Vaultiq cannot recover or reset it, and nobody else can.
Install the browser extension
One build works in both Firefox and Chrome. There is no store listing yet, so you build it from source.
Build it
You need Rust (with the wasm32-unknown-unknown target), wasm-pack, Node 24
and pnpm.
git clone https://github.com/rustiqz/Vaultiq.git
cd Vaultiq/extension
pnpm install
pnpm run build # output in extension/dist
Load it in Firefox
- Open
about:debugging. - Choose This Firefox, then Load Temporary Add-on.
- Pick
extension/dist/manifest.json.
Temporary add-ons are removed when Firefox restarts, so you repeat this after each restart.
Load it in Chrome
- Open
chrome://extensions. - Turn on Developer mode.
- Choose Load unpacked and pick the
extension/distfolder.
Other Chromium browsers are untested.
First run
Open the Vaultiq toolbar popup and choose Create your vault. Pick a master password and decide whether to use the vault without a server.
If you already have a vault on a server, use Join with a token instead; see Connect your devices. If you have an exported backup, use the Restore backup tab on the welcome screen.
Install the Android app
The Android app is built from source and installed as a debug APK. It targets arm64 devices. There is no store listing yet.
Build it
You need Rust with the aarch64-linux-android target, the Android SDK and NDK,
Node 24 and pnpm.
git clone https://github.com/rustiqz/Vaultiq.git
cd Vaultiq/mobile
pnpm install
pnpm run crypto # cross-compile the core, generate Kotlin bindings
cd android && ./gradlew assembleDebug
The APK is in app/build/outputs/apk/debug/. Install it with adb install or
copy it to the phone.
First run
Choose one of the options on the first screen:
- Create a vault on a server you run (needs an invitation token).
- Join an existing vault by scanning a QR code from the extension’s Add a device, or by pasting a token.
- Use without a server for a local-only vault.
- Restore from an exported backup. A restored vault is always local-only.
Turn on Android autofill
Vaultiq fills logins in other apps through Android’s autofill service. Switch it on in system settings: Settings → Passwords & accounts → Autofill service (the wording varies by device), then choose Vaultiq. See Autofill and saving logins.
Fingerprint unlock
After you unlock with the master password once, enable fingerprint unlock in Settings. See Unlocking and locking for how it works and what invalidates it.
Deploy the server
The server is NestJS and PostgreSQL, run with Docker. The compose file starts three containers: Postgres, the server, and Caddy, which obtains its own certificate. Only Caddy is published; Postgres and the server are reachable only on the internal network.
Before you start
- A machine with Docker and Docker Compose.
- A domain name pointing at that machine, with ports 80 and 443 reachable. Caddy needs both to obtain and renew its certificate.
Start it
git clone https://github.com/rustiqz/Vaultiq.git
cd Vaultiq
cp .env.example .env # set POSTGRES_PASSWORD and VAULTIQ_DOMAIN
docker compose up -d
Set POSTGRES_PASSWORD to something long and random, and VAULTIQ_DOMAIN to
your domain. Keep .env private and out of version control.
Get the first invitation
Registration is invite-only. On a fresh server with no accounts, the server mints one registration token at boot and writes it to its log:
docker compose logs server
Use that token to create your account from the extension or the Android app. After that, issue more invitations with the admin CLI.
Check that it is running
curl https://your.domain/health
docker compose logs server | head -1 # vaultiq-server <version> listening on 3000
The first line of the log names the running version.
Things worth knowing
- The server sits behind Caddy and trusts exactly one proxy hop, so rate limits and the audit log see real client addresses. Do not put another proxy in front without understanding that.
- Each vault is limited to 10,000 items.
- Back up the Postgres volume if you want the server’s copy preserved. The contents are ciphertext, so a backup of it does not expose your passwords, but it is useless without the master password.
- Updating: pull the new version, then
docker compose up -d --build. Migrations run at boot and are safe to repeat.
Invitations, users and devices
Administration is a terminal wizard that runs inside the server container. It has no web interface and no HTTP surface, so there is nothing to expose.
docker compose exec server node dist/admin/cli.js
An administrator can issue invitations and revoke devices. An administrator cannot read anyone’s vault: the server never has the keys.
What the menu does
| Entry | What it does |
|---|---|
| Invite someone | Creates a single-use registration token. You choose how long it stays valid (1 hour, 24 hours or 7 days) and which capabilities the new account gets. The token is shown as text and as a QR code. |
| List users and devices | Shows every account and the devices enrolled on it. |
| List outstanding invitations | Shows tokens that have been issued and not yet used or expired. |
| Revoke a user | Revokes every device on the account and spends its outstanding device-join tokens. |
| View audit log | Shows the security event history. |
| Prune audit log | Deletes audit entries older than a number of days you choose. Retention is manual. |
| Recover a locked-out account | Present but does nothing. See below. |
Capabilities
Accounts can carry capabilities that describe what an administrator may do: manage invitations, manage devices, view the audit log. They are granular, not all-or-nothing.
The audit log
The log records registrations and enrolments (including refusals), device revocations, master password changes and invitations issued. It never records a credential, token or key. Source IP addresses are recorded only for refused registrations and enrolments, so abuse can be traced.
Locked out? There is no recovery
If someone forgets their master password, nobody can recover their vault. The server holds no copy of the key and there is deliberately no escrow. The “Recover a locked-out account” entry exists so that its absence is not mistaken for a missing feature. The only way out is an encrypted backup plus the password that opens it.
Revoking a single device
Users can revoke their own devices from the app: the device list in Settings on Android, and in the extension’s Settings.
Connect your devices
First device
In the extension, create a vault and unlock it. Open Sync, enter the server address, name the device, and choose Set up a new server. This uploads the vault as it stands. Registration needs an invitation token: a fresh server logs one at first boot, and the admin CLI issues more.
On Android you can instead choose Create a vault on the first screen, which generates the vault on the phone and registers it with the token.
Adding a second device
Enrolment needs both a token and the master password. Either alone is not enough.
- On a device that already has the vault, choose Add a device (extension) or Invite a device (Android Settings). A QR code appears.
- On the new device, choose Join with a token (extension) or Join (Android) and scan the QR code, or paste the token. The QR carries only the server address and the single-use token, never the master password.
- Enter the master password on the new device.
Tokens are single-use and expire after a short time. If one expires, make another.
When sync happens
Sync runs when you unlock and shortly after any change. There is no periodic background sync, because that would mean keeping the vault key alive on a timer. Edits made on two devices at once are never silently overwritten: the extension keeps both copies of a conflicting item.
Moving a local vault onto a server
In the extension, a local vault can be connected to a new server and uploads as-is, unless Never sync this vault is on. On Android there is no conversion: restore a backup or re-create the items.
Changing the master password
Settings → Master password, in either app. Items are not re-encrypted, so nothing re-syncs. Other devices keep syncing and ask for the new password at their next unlock. Outstanding device tokens are spent by the change. There is no way back to the old password.
Items and what they hold
A vault holds five types of item. All are encrypted the same way, and the type is bound into each item’s authentication tag, so a server cannot relabel one.
| Type | What it holds | Autofills |
|---|---|---|
| Login | Username, password, site | Yes, on its own site only |
| Card | Cardholder, number, expiry, security code, optional PIN | Yes (extension) |
| Identity | Name, company, email, phone, address, date of birth, national ID | Yes (extension) |
| Authenticator | A TOTP secret and the shape of its codes | Yes, into a one-time-code field (extension) |
| Secure note | A name and free text | No |
Creating and editing
Use the New item button (the extension’s header, or + on Android’s Vault screen) and pick a type. The same form edits an existing item. Fields you use every time are always shown; the rest start as add-chips and become fields once tapped.
Every change is stored as a new encrypted version of the item. Nothing is modified in place.
Deleting
Deleting moves an item to Trash, where it can be restored. Emptying it, or purging one item, is permanent: the content is replaced and cannot be recovered.
Copying secrets
Copy buttons put a value on the clipboard. On Android the clipboard is cleared after 30 seconds, but only if nothing else was copied in the meantime.
Favorites and sorting (Android)
Tap the heart on an item to favorite it. The Vault list sorts last-used first by default, and that history stays on the device.
The Android layout
The bottom tabs are Vault (logins, with tiles for Cards, Identities and Notes), Codes (live authenticator codes) and Settings.
Autofill and saving logins
In the browser
When you focus a sign-in field, the extension offers matching logins. A login is offered only to the site it belongs to. Cards and identities have no site, so the same card can be used anywhere, but nothing is offered until you focus a field that asks for it, and no value leaves the background until you pick one item by hand.
The popup also has a Fill on this site action for the active tab.
When you sign in somewhere new, or change a password, the extension offers to save it.
On Android
Vaultiq is an Android autofill service for logins. Turn it on in system settings (see Install the Android app).
When a sign-in form appears, Android shows one suggestion, Fill with Vaultiq. Tapping it opens Vaultiq over the form. If the vault is locked you unlock it first (fingerprint or password). Then you see up to three matches, each with a Fill button, plus Search vault and Save new.
When you sign in to a new app or site, Android’s own “Save to Vaultiq?” prompt leads to a confirm sheet in Vaultiq.
Check who is asking
The sheet always shows who requested the fill. For a browser page it shows the verified website domain. For a native app it shows the app’s name and package, marked Not a verified website. A fake app can imitate a login screen, so read that line before you fill.
Limits
Identity and card autofill on Android is not built. Autofill never fills into Vaultiq’s own unlock fields.
Unlocking and locking
Your master password unlocks the vault. Everything else here is a convenience layered on top.
Auto-lock
Both apps lock after a period of inactivity. The default is 15 minutes.
- Extension: set it in Settings. A locked vault drops the keys from memory.
- Android: choose 1, 5, 15 or 30 minutes, or never, in Settings → Auto-lock. The timer runs while the app is in the foreground; if Android kills the app in the background the key is gone anyway.
PIN (extension)
A PIN lets you unlock the extension without typing the master password. It is session-only: it lasts until the browser closes, after which you need the master password again. Set it under Settings → Quick unlock PIN.
Fingerprint (Android)
After one password unlock, enable fingerprint unlock in Settings. Your master password is then cached encrypted under a key in the Android Keystore that needs your fingerprint for every single use. A fingerprint cannot derive your key by itself; it only releases the cached password.
If you add or remove a fingerprint on the device, the key is invalidated and Vaultiq asks for the master password again. That is intended: a newly added fingerprint must not inherit access.
Changing the master password
Settings → Master password, in either app. You need the current password. No items are re-encrypted. If a server is connected, it is updated first, then the local copy. There is no way back and no recovery.
Theme
Both apps follow the system light or dark setting. Android also has a manual override (System, Light or Dark) in Settings.
Authenticator codes
Vaultiq can hold time-based one-time passcode (TOTP) secrets and show the 6-digit codes, the same as an authenticator app. Codes are computed in the shared Rust core and checked against RFC 6238’s published test vectors.
Add an account
- Paste an
otpauth://link. The link an issuer shows beside its QR code carries the algorithm, digit count and period, so nothing is guessed. - Type the secret. Anything under 16 bytes is refused as too short.
- Scan a QR code (Android). The Codes tab, and the new item form, open the camera.
Using codes
On Android the Codes tab lists every authenticator account with its live code and a countdown ring. Tap a code to copy it; the clipboard clears after 30 seconds. Codes are grouped by account.
In the extension, an authenticator item autofills into a one-time-code field on the page.
A caution
Keeping your passwords and your second factor in the same vault means one master password protects both. That is a trade-off, not a flaw, but decide on it deliberately for your most important accounts.
Import, backup and restore
Import
Vaultiq imports from a file you export from another manager or browser.
| Format | What comes across |
|---|---|
| CSV (Chrome, Firefox, Bitwarden, LastPass, 1Password and similar) | Logins and secure notes |
| Bitwarden JSON | Logins, secure notes, cards and identities |
| Proton Pass JSON | Logins and secure notes (trashed items are skipped) |
Rows of any other type are skipped and counted, never guessed at. Authenticator secrets are not imported from any format.
Extension: overflow menu → Import. Android: Settings → Import from file. Pick the file; Vaultiq detects the format.
You then get a preview list with a checkbox on each row. Vaultiq checks each row against what is already in your vault:
- An identical item is unchecked by default, so a repeat import does not clutter the vault.
- An item that looks like the same account but differs (a password changed since the export, say) is checked by default and imported as a new item. A Replace the existing entry toggle updates the old one instead. Vaultiq never silently overwrites.
Delete the export file once you have confirmed the import. It is plain text, with your passwords in it, and it sits outside Vaultiq’s control as soon as you create it.
Formats are read from their documented structure. If a migration looks wrong, check the preview before importing, and keep the original manager until you are sure.
Backup and restore
An exported backup is a single file holding your wrapped vault key and every item, all still encrypted. It is the only way to get a local-only vault off the device, so make one regularly.
- Export: the extension’s overflow menu → Export backup; Android Settings → Export backup. Trashed items are included.
- Restore: the extension’s welcome screen → Restore backup; Android’s first screen → Restore. You enter the backup’s master password, which is checked before anything is written.
Things to know:
- A backup needs the master password it was made under. A backup does not rescue a forgotten password.
- A backup file is not encrypted a second time, because every field in it is already ciphertext or a wrapped key. Anyone holding the file can try to guess the master password offline, so store it as carefully as the vault itself, and choose a long password.
- On Android, exporting a server-backed vault first syncs, so it needs a connection. A local-only vault exports straight from the device.
- Restoring on Android always creates a local-only vault, even if the backup came from a server-backed one.
- Restoring in the extension needs an empty profile: it refuses to overwrite an existing vault.
What Vaultiq protects, and what it does not
This is the short version for users. The full threat model, including the key hierarchy and every scenario, is SECURITY.md.
How it works, briefly
Your master password is stretched with Argon2id into a master key. Two independent keys are derived from it with HKDF: an auth key, the only thing that ever leaves your device, and an encryption key that wraps a random vault key. Items are encrypted under the vault key with XChaCha20-Poly1305, with each item’s id and version bound in so a ciphertext cannot be swapped for another.
The server never sees the master password, the master key or the vault key. The cryptography lives in one Rust core shared by every client, which makes no network calls.
Defended against
- A compromised or curious server. It holds only ciphertext and a wrapped key.
- A stolen database or backup file. Useless without the master password.
- Tampered or swapped ciphertext. It fails authentication instead of decrypting.
- Network eavesdropping. Beyond TLS, the contents are already encrypted.
Not defended against
- A compromised device. Malware or an attacker who can read the app’s memory while it is unlocked sees what you see.
- A keylogger, or someone watching you type the master password.
- A weak master password. Argon2id slows guessing; it cannot stop a guessable password being guessed.
- Metadata the server must see: how many items you have, their sizes and when you sync.
- You forgetting the master password. There is no recovery and no escrow.
- Phishing and fake apps that fool you into filling a password. Autofill shows who is asking on Android; read it.
Be honest about the maturity
Vaultiq has not been independently audited. One person wrote it. If that matters for what you store, use a product that has been audited.
Report a vulnerability
Do not open a public issue. Follow the private reporting steps in SECURITY.md.
Troubleshooting and FAQ
Questions
What if I forget my master password? The vault stays locked. Nothing can reset it, because nobody can read the vault, you included. Backups do not help: they still need the master password.
Can the server operator read my passwords? No. The server holds sealed items and a wrapped key, never the keys to open them. It can see how many items you have, their sizes and when you sync.
Does it phone home? No telemetry, analytics or update checks. The crypto core makes no network calls at all, and the apps talk only to the server you point them at, if any.
Can several people share one server? Yes, by invitation. Each person has a separate vault the others cannot read. Sharing items between people is not built.
Can I move from local-only to a server later? In the extension, yes, unless Never sync this vault is on. On Android there is no conversion.
Is there an iOS app? No. Today it is Firefox, Chrome and Android.
Is it free? Yes. It is licensed under the AGPL-3.0. There is no hosted service; you run the server yourself.
Troubleshooting
Registration is refused.
You need a valid, unspent registration token. A fresh server logs one at boot
(docker compose logs server); the admin CLI mints
more. Tokens expire.
Joining a device fails. A device-join token is single-use and short-lived, and enrolment also needs the master password. Make a new one with Add a device.
The server certificate is not issued.
Caddy needs VAULTIQ_DOMAIN to resolve to the machine and ports 80 and 443 to
be reachable. Check docker compose logs caddy.
A version conflict appears when saving. Another device saved the item first. In the extension both copies are kept; on Android reload and re-apply your edit.
Firefox removed the extension.
Temporary add-ons are removed on restart. Load it again from about:debugging.
Autofill does not appear on Android. Check that Vaultiq is selected as the autofill service in system settings, and that the form has a username and password field. Detection relies on the field hints the app or browser provides, so a few older forms are missed.
Fingerprint unlock asks for the password. The device’s enrolled fingerprints changed, which invalidates the cached password on purpose. Unlock once with the master password and turn fingerprint unlock on again.
Still stuck? Open an issue. Support is best effort, and a vulnerability goes through SECURITY.md, not an issue.