Password managers: KeepassXC and Vaultwarden

Password manager requirements

Password managers are a necessary tool for keeping accounts secure. The usual recommendation is to use a unique password per site, to have it randomly generated, and to never type it manually or copy/paste using the standard clipboard (because malware watching the clipboard is a thing). The best way to solve all these with reasonable usability are password managers with direct web browser integration. For other applications (e.g. desktop applications that take credentials to log into their respective servers), copying via the clipboard is probably unavoiable (barring constructions with calling a password manager binary as stdin), but for the overwhelming majority of login interactions throughout the typical day, the web browser or integration into the respective platform password API (e.g. Android) should be the focus.

To summarize, I generally have the following requirements for password managers:

  • Open source client with local end-to-end encryption of all data (passwords, user names, notes, etc.) and meta data (URLs associated with accounts, last used date/time, etc.)
  • Secure cryptographic primitives for encryption (i.e. AES), integrity protection, and password-based key derivation (e.g. Argon2)
  • Support for the main OS platforms, at least Linux desktop, Windows, and Android for my work group and direct family - plus MacOS and iOS for extended family members
  • Support for storing Passkeys (test e.g. here) and TOTP tokens
  • Possibility to sync password databases between multiple devices
  • Offline capability to use the locally synced database without network connectivity - at least read only, even better if changes can also be made offline for later syncing
  • Ideally, self-hosting the sync server for further attack surface reduction against high-impact single-point attacks even when the actual data is end-to-end encrypted with a strong master passphrase
  • Usability features like flexible random password generators and integration with password leak databases like HaveIBeenPwned
  • A decent history of the respective project/company in dealing with vulnerabilities, and no history of embarrassingly bad security issues and/or bad behavior in dealing with midly bad issues

That does not leave a lot of choices; after following the domain for many years, my only recommendations based on these requirements at the time of this writing are KeepassXC and Bitwarden/Vaultwarden.

KeepassXC

In contrast to the original Keepass2, which is based on .NET/Mono, the KeepassXC client application is implemented in C++ for all major desktop platforms, and smartphone apps supporting the same database format are broadly available. For Android, I personally use Keepass2Android. Integration with web browsers (Firefox and Chromium based ones) is provided through the KeepassXC Browser Extension. As of version 2.7.7, KeepassXC also supports storing Passkeys.

Advantages

  • Simple to manage and to recover from disasters: The whole database is a single file that can be easily copied around, backed up, archived, shared with others through any potential means, etc. In case of a disaster, if that single file and the master passphrase is available, a compatible application (KeepassXC or any other one using the KDBX4 format) can be easily found and no further recovery steps are necessary. Just open the file, enter the passphrase, and everything is back up and running.
  • Flexible: KeepassXC in particular supports multiple forms of authenticating/unlocking the password database including e.g. Yubikeys as well as storing different authenticator types (e.g., Passkeys or SSH keys, even being able to act as an ssh key agent directly). Through the keepassxc-cli command line tool, it can be integrated in arbitrary scripts or called from other tools for accessing passwords without copy/pasting them. There are different import and export format options for moving from/to other password managers.
  • Usable security: The native applications integrate well with the respective native desktop environments. Browser extensions connect to the locally running application. Many settings can be tweaked for the local use case, and e.g. the basic auto-locking the database on laptop suspend or system screen lock or auto-clearing passwords copied to the clipboard after a timeout work reliably on all platforms I have tested it with. Reasonable keyboard shortcuts (e.g. Ctrl-B for copying the user name) make it really quick to use. Checking all passwords with HaveIBeenPwned is directly integrated, as are nice local-only reports and usage logs.
  • Offline support: If required in some workflows, KeepassXC can easily be used on completely offline systems.

Disadvantages

  • Synchronization requires extra work: KeepassXC is a client-only application dealing with simple files and does not directly implement any cross-device synchronization. That is left to the user to figure out. There is a rudimentary KeeShare mechanism to share subsets the password database with other users, but it also uses files for exchanging this data. However, merging changes made in two different versions of the database works well and has so far been completely reliable.

If users can deal with managing files and sychronizing them between devices on their own, KeepassXC is the most simple, secure, and stable option I have found so far; and I have been using it myself for a long time. In my workflow, synchronization between desktops happens through Git (with the KDBX file checked into a dedicated repository, with the added advantage of history and implicit backup), and to smartphones through Syncthing. This works well for my daily use, but is not useable enough for non-technical users without help.

Vaultwarden/Bitwarden

Bitwarden also offers open source clients for all major desktop platforms (unfortunately written as Electron app, with all the associated disadvantages), self-contained browser extensions not reliant on the desktop applications, and the smartphone platforms Android and iOS as well. For bonus points, they even offer the Android APK in their own F-Droid repo. There is also a command line client.

Bitwarden itself supports self-hosting, but with notable hosting requirements and potentially requiring a license (e.g. for enhance sharing features). Vaultwarden is a lightweight, compatible server implementation of the Bitwarden API written in Rust. I have been using a locally hosted Vaultwarden server in a single Docker container (running under gVisor as another layer of defense for a publicly reachable web service) with minimal resources and the official Bitwarden clients on multiple platforms, and it has been stable so far.

Advantages

  • Easy sychronization: For initial setup, installing the official client app for the respective platform, selecting self-hosted, entering the server FQDN, then entering the email address that identifies the account on the server, and performing a first authentication is sufficient to achieve full client integration. This is much simpler for non-technical users than first having to figure out an independent synchronization mechanism, installing the application, locating the right file from the out-of-band synchronization directory, and then dealing with merging changes between the devices.
  • Sharing of passwords: For sharing passwords between multiple users, e.g. in a work group or family, Bitwarden/Vaultwarden have built-in support of “organizations” and “collections” within organizations that make organized sharing easy und understandable.
  • Web application with 2FA: In disaster or emergency situations when none of the previously used client devices remains available (but the self-hosted or Bitwarden server is still running), passwords can be accessed through the web application, optionally secured with two-factor authentication. I use WebAuthn with multiple registered Yubikeys in my own setup. To disable 2FA, a recovery code can be created - and, e.g., printed out and stored in a safe, is another layer of disaster recovery that could be helpful in organizations.
  • Ease of use: The clients are simpler than KeepassXC and therefore don’t overload users with options. Browser extensions don’t require a local application (with setup of the connection between them), but are self-contained.
  • Option to get professional hosting with support: For users who don’t want to deal with self-hosting and would like professional support, the company behind Bitwarden offers that.

Disadvantages

  • Not as flexible: The Bitwarden clients can store Passkeys (supported earlier than KeepassXC, which only got Passkeys support very recently) and TOTP tokens, but e.g. no SSH keys. There are also very limited options in the clients, and no reports like KeepassXC offers them or integration with HaveIBeenPwned. That said, the Vaultwarden web interface offers HIBP checking and other reports.
  • Not quite as secure: Running the full client code inside the web browser with the self-contained extensions exposes all the data, including the master passphrase, to potential browser bugs. Web browsers are the most complex and most exposed applications on modern desktops/smartphones, and therefore a massive attack surface. While Chromium based browsers operate a decent sandbox, that is still architecturally less separated than a completely different application like the KeepassXC native client communicating with the browser through a tight, custom RPC interface. Bitwarden clients and Windows and MacOS seem to support such an integration between the browser extension and the native application, but as the Linux one doesn’t, I couldn’t yet try this out myself. Also, Electron is massively more complex than a small C++ application.
  • Not as integrated into native desktop environments: The Electron desktop applications do not integrate as well as KeepassXC. Yes, they offer a tray icon, but I was so far unable to get the (Flatpak) Linux client to auto-lock on system session lock (e.g. suspend or screen lock) and therefore set a short 15 minute auto-lock period. That is both potentially less secure and is definitely less usable than the native KeepassXC locking integration. As mentioned above, there is no integration as an ssh key agent, as there is no SSH key support.
  • Requires a running server and online connectivity: While desktop/smartphone clients can access a previously synced state of the database offline, this access is read-only. For editing anything, an online connection to the running server is required. This may be problematic for users who are offline during their typical workflows and need to add/edit accounts during that time. It also means that disaster recovery is more potentially involved if the disaster takes the server offline.

Disaster recovery

Passwords are important. If anything unexpected happens, they are required to recover from that situation. That places a special burden on a good plan for recovery of the password database itself. Note that disaster scenarios can be manifold, including but not limited to loss of client devices, loss of servers, loss of network connectivity, and loss of life of the database owner - which implies loss of memory of the master passphrase.

For KeepassXC, the disaster backup plan is a USB stick with a single KDBX file on it (maybe including the self-contained KeepassXC binaries for different platforms), stored in a secure place. To safeguard against loss of memory of the master passphrase, that passphrase can be printed out on paper and stored in the same or a different safe place (or, depending on your threat model, potentially be distributed in multiple shares among friends/family for a k-out-of-n recovery scheme). Any person with some limited technical knowledge will be able to recover passwords from that (assuming knowledge of the master passphrase) with very limited help and without additional infrastructure.

For Vaultwarden, this is a bit more complex. My current disaster recovery plan is a copy of the data volume of the Vaultwarden docker container, which can be used locally on a Linux laptop with a simple one-liner:

`podman run -p 9280:80 -v ~/private/vaultwarden/data/:/data/ docker.io/vaultwarden/server:latest`

In my setup, the other meta data for the container including the .env file is stored in a Salt stack configuration and therfore not backed up explicitly in this disaster recovery plan. Depending on your setup, this might need to be included in the backup as well. Also note that depending on the database backend, copying the data volume may not be transaction safe and I refer to the Vaultwarden backup documentation for details.

Note that for accounts that have 2FA authentication enabled, e.g. with WebAuthn, login will fail because the server FQDN will have changed when accessing the localhost service. Therefore, the “Bitwarden two-step login recovery code” needs to be stored (e.g., printed on paper) as well for each user account that uses 2FA (and I am not talking about host name resolution trickery here, because that is harder to document and not part of a simple recovery plan). This will allow basically read-only access to passwords, and can be used to bootstrap another self-hosted server. However, merging locally made changes during the disaster situation with a still-running or restarted server will probably be tricky or impossible in an automated manner. I have not tried how well all of this works on an offline laptop without infrastructure access at the time of this writing.

Conclusions

I am in the process of migrating a large set of passwords and other secrets from KeepassXC to Vaultwarden/Bitwarden because of ease of use for other work group and family members and much better sharing support. In a group of more than one technical user, it offers easier-to-explain workflows.

However, for some core passwords that are required to bootstrap others or for special passwords with higher security requirements, I will most probably still keep a core KDBX file managed and synchronized manually with KeepassXC.

René Mayrhofer
René Mayrhofer
Professor of Networks and Security & Director of Engineering at Android Platform Security; pacifist, privacy fan, recovering hypocrite; generally here to question and learn