Add the user option to disable the requirement of having to use the Master Password upon initial Bitwarden windows desktop application startup, and use Windows Hello/biometrics instead….as was available in earlier versions of the application. And this would be similar to initial application startup in Apple OS which allows the use of biometrics. This would allow for greater efficiency and allow users the choice of accepting the level of security Windows Hello provides on initial application startup.
1 Like
@Merlwynd Welcome to the forum!
There is no such requirement to use the master password - you (still) can also use PIN unlock for the first unlock of the desktop app.
And there already is a pull request to reintroduce biometric unlock on app start:
main ← km/poc-windows-hello-2
opened 06:44PM - 27 Aug 25 UTC
## 🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-25373
## 📔 Object… ive
> [!NOTE]
> QA testing is still pending for whether the focus issues from https://github.com/bitwarden/clients/issues/13291 are still fixed with this PR.
> [!NOTE]
> Pending verification, the windows-hello key derived from signature will be replaced by PRF passkey gated by Windows Hello, once that becomes available.
This PR started as a research spike for the following goals:
1. Establish a good abstraction for biometrics, pushing all details to rust. The typescript code is minimal / just pass-through. This is intended to also be the abstraction for the mac-rewrite to SecItem
2. Evaluate bringing back unlock on app start on windows
- This needs more layers of unstable workarounds / hacks to fix the broken focus behavior of the Windows-Hello signing API
4. Evaluate anti-memory dumping techniques, to protect ephemeral biometric secrets in locked vaults
In the process, this completely re-writes the windows hello implementation from the ground up. And mostly re-write the linux implementation. Both are significantly simpler to understand, while at the same time being more robust, and more secure. All complex concepts like "clientKeyHalf", "osKeyHalf" are dropped in favor of better abstractions.
Both Windows and Linux are re-written at the same time here in order not to have to keep around multiple abstractions as an intermediary step.
### Windows Implementation
The windows implementation now has two paths. One for after first unlock, and one for on first unlock after app restart.
#### UV unlock (AFU)
The windows implementation now stores the keys protected using DPAPI memory encryption in memory after first unlock. This prevents access by memory dumping, closing existing attack vectors. It is possible this can still be cricumvented by injecting DLLs into the process. This will path will be closed down here: https://github.com/bitwarden/clients/pull/16156
#### Signing unlock (BFU)
Here the signing API is used as was the case before https://github.com/bitwarden/clients/pull/14953. A challenge (per-user) is signed. This signature is then hashed to derive a key. This key is used to decrypt the userkey. The userkey ciphertext + challenge + nonce are stored on the keychain, that is user-wide accessible.
#### Focus issues
https://github.com/bitwarden/clients/pull/14953 had to remove the signing API due to issues focusing. This PR adds additional unstable workarounds - such as attaching to the currently foregrounded window's thread - to force focus the windows-hello prompt. Once Microsoft releases the new API, this code will be replaced by the stable API that does not have focus issues.
Further, an additional feature is added - when the authentication starts, the currently foregrounded window is saved. After the authentication is done, that window is foregrounded + focused again. This makes it so that an extension / browser is properly re-focused.
### Linux Implementation
Pretty much the same as before, but instead of using libsecret + a client-side unprotected secret, which can be easily circumvented using memory dumping (on snap), memfd_secret is used alone. The userkey is directly stored to a hashmap that is protected with memfd_secret.
### Memory Protection
This add support for [DPAPI's](https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectmemory) memory encyrption, and [Linux's memfd_secret](https://man7.org/linux/man-pages/man2/memfd_secret.2.html). These are currently only used to hold the ephemeral keys for unlocking with biometrics, but will be used in more areas like SSH-agent in the future.
### Security
The security goal here is to prevent user-space apps from bypassing lock, which is not currently consistently possible with the current implementation. The attacker model here is user-space processes. A kernel or administrator account compromise is not specifically defended against / best-effort.
Both implementations, AFU, are protected with memory protections. As mentioned, debuggers/dll injection are still a problem on Windows, which will be dealt with in a [separate PR. ](https://github.com/bitwarden/clients/pull/16156) User-space applications can thus no longer access the keys required here, and thus to circumvent the unlock, Windows Hello / Polkit would need to be attacked directly.
For Windows-Hello BFU (on app start), a per-user challenge is signed with the Bitwarden-desktop signing key. The deterministic signature is hashed to obtain the Windows-Hello key. (Challenge, windows-hello-key-wrapped-userkey, encryption nonce) `WindowsHelloKeychainEntry` , are stored on the Windows keychain.
The security model here relies on the assumption that a user does not accept an unexpected Windows Hello prompt. To break the security, an attacker has to obtain the `WindowsHelloKeychainEntry` from the keychain (accessible to any userspace process). Subsequently, they have to phish a Windows-Hello prompt with the Signing API for the challenge. That is, a successful Windows-Hello authentication is required.
### Testing & Docs
This significantly increases the documentation for how the implementations work. Both Linux and Windows should be comprehensible with minimal background knowledge now. Manual tests are provided for polkit / windows hello, so these can be easily tested. Automatic integration-tests for rust are sadly not possible still, since it is unclear how the Windows-hello prompt would be emulated.
## 📸 Screenshots
https://github.com/user-attachments/assets/618072ea-7e8e-4e94-8968-14adfcee22ec
## (Unsigned commits)
> [!NOTE]
> If you're wondering about the unverified commits, I don't have signing set up on Windows. LMK if you require me to re-push a signed history.
## ⏰ Reminders before review
- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team
## 🦮 Reviewer guidelines
- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
PS: And…:
main ← km/pm-25373/windows-bio-v2
opened 07:12PM - 15 Sep 25 UTC
## 🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-25373
## 📔 Obje… ctive
Extracting out the Windows rewrite from https://github.com/bitwarden/clients/pull/16187 and putting it behind its own feature flag.
## 📸 Screenshots
## ⏰ Reminders before review
- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team
## 🦮 Reviewer guidelines
- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
Yes, thanks…but I don’t want to use a PIN. I would like to use Windows Hello…which is secure enough to unlock my entire laptop…so I feel it is secure enough (for me anyways) to unlock Bitwarden. I do not wish to yet have another PIN to remember and use. This was available in Bitwarden a few revisions ago and seems to have been changed. I did not see the request you mentioned above when I did a search,…guess my searching skills need improvement. Not sure what a “pull request” means vs how I requested it?
dwbit
September 17, 2025, 10:38pm
4
Hi @Merlwynd , and thanks for the feedback! The team is exploring ways to bring back this functionality securely and reliably, so stay tuned!
In the meantime, as @Nail1684 mentioned, you can use pin just for the initial ‘on app restart’ and then using biometrics as usual after that, thanks for your patience!
1 Like