* Allow email-only /api/two-factor/send-email-login for mobile clients
Mobile clients (iOS) may call /api/two-factor/send-email-login with only the user's email and without a MasterPasswordHash or an AuthRequest. Permit email-only requests so the server will send the email 2FA token in that flow.\n\nModified: src/api/core/two_factor/email.rs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(email-2fa): use device-identifier fallback when no password hash submitted
iOS clients call /api/two-factor/send-email-login with an email and
DeviceIdentifier but without masterPasswordHash or authRequestId after
receiving a 2FA-required response from the token endpoint. The previous
empty else-block allowed any caller to trigger a 2FA email for any
account knowing only the email address.
Replace the empty block with a device-identifier-based fallback:
- Look up the most-recently-active device via find_by_device_for_email2fa.
- Verify the device's associated user email matches the submitted email.
- Log (debug) when the fallback path is exercised for operator visibility.
- Reject with the original error when no device identifier is provided or
when the device maps to a different account.
Fixes#7568
* Check the pending 2FA login for this user and device
Look up the pending 2FA login for the user and device instead of the
latest one on the device, answer a failed check with the same error and
IP/username log detail as a wrong password, and escape the device id in
the logs.
---------
Co-authored-by: Arunabha-Mukhopadhyay <dkarunabha2006@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* 2FA using userVerificationToken
* Fix 2FA Yubikeys
* TwoFactor.find_by_user_and_type take enum parameter not i32
* log_user_event take enum parameter not i32
* Fix 2fa webauthn
* Prevent 2FA claims reuse
* 2fa webauthn return keys when deleting
* 2fa reset twofactor_remember
* Reject 2FA verification tokens issued for another provider
The Email and Duo claims only have optional fields, so a userVerificationToken minted for another
provider deserialized into them and was accepted. Each provider's claims now reject unknown fields,
with a test that every token only parses as its own provider.
Also fix the email 2FA login in the Playwright user setup, which used an undefined `mailBuffer`.
---------
Co-authored-by: Timshel <timshel@users.noreply.github.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
* Support new account recovery password payload
* Address account recovery review feedback
* Check the account recovery password before sending the recovery email
---------
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
Both notification hubs send a Ping every 15 seconds but ignore the
Pong, so the loop only ends on a Close frame, EOF or a socket error.
When a client disappears without the TCP connection being closed, for
example behind a reverse proxy or CDN that keeps the upstream
connection open, none of these ever happens. The connection, its file
descriptor and its map entry are then kept forever, until the process
runs out of file descriptors and stops accepting connections and
opening the database.
Keep track of when something was last received from the client, Pongs
included, and close the connection when nothing was received for 30
seconds. This is the default ClientTimeoutInterval of ASP.NET Core
SignalR, which the official server uses.
Fixes#7805
Co-authored-by: Cassian433 <262026629+Cassian433@users.noreply.github.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
- Attachments: reject a declared v2 attachment size above the upload limit,
keep display sizes within the largest unit, and make download links valid
for 1 minute like upstream.
- Ciphers: moving a personal cipher into an organization needs collection
write access or full access, like upstream.
- Events: /events/collect only accepts the client event types upstream accepts.
- Client IP: for list headers like X-Forwarded-For, use the rightmost address
that isn't in IP_HEADER_TRUSTED_PROXIES, reading every occurrence.
- Prelogin: unknown emails get stable KDF settings from upstream's list.
- Login with device: an auth request can be used for one login, like upstream.
- Directory Connector import: never revokes, restores or removes Owners,
like upstream.
- SSO: check the PKCE verifier again when the code exchange is reused during
2FA, and accept the same redirect URIs as upstream (desktop localhost
callback for AppImage and dev builds, CLI on ports 8065-8070).
- Identity: send the merged master password policy in the 2FA response and
use PascalCase policy keys in identity responses, like upstream.
Organization API key login no longer needs device fields. Recovery code
login normalises the code, uses upstream's error message, logs a failed 2FA
event and sends a "two-step login recovered" email.
- Add GET /api/accounts/keys.
- Return errors instead of panicking on malformed event dates, cipher data,
key rotation cipher ids, bulk confirm entries and YubiKey OTPs.
Remove endpoints, response fields, feature flags and compatibility code
that upstream Bitwarden has removed and that no current client uses:
- Legacy POST /identity/accounts/register and POST /api/accounts/prelogin;
register/finish is rate limited like the other unauthenticated endpoints.
- Legacy organization routes: PUT groups/{id}/users, PUT policies/{type}/vnext,
PUT users/{id}/reset-password, GET billing/metadata, and the POST aliases of
the organization, collection, group and member PUT/DELETE routes.
- POST /two-factor/disable (PUT stays).
- ResetMasterPassword, captchaBypassToken, the legacy registration name field,
userIsManagedByOrganization/managedByOrganization and accessAll.
- The automatic email 2FA code for clients older than 2025.5.0.
- DUO_USE_IFRAME and the Duo Traditional Prompt code.
- Experimental client feature flags that no client reads anymore.
- Web vault CSS selectors for web vaults older than 2025.5.1.
Also accept the PascalCase fields Android 2026.9.0+ sends on registration
and password change, and align a few account, login/2FA and organization
checks with upstream.
Adds tests for the registration body formats.
Introduced in Browser 2026.2.0 via bitwarden/clients#18395. Rewrites the
post-submit add/update login notification triggering logic, deferring
cipher-type inference until the vault is unlocked. Client-side only.
When using xx-cargo it uses a different linker then the default one.
This causes some default fixes Debian/Ubuntu add for the Cortex-A53
architectures to not be included.
This commit fixes that by checking if the target architecture is arm64
and if so, will add the needed fix argument. This should prevent issues
reported here #7754.
We can not say this with 100% certainty since this bug sometimes appears
and sometimes it does not.
Fixes#7754
Signed-off-by: BlackDex <black.dex@gmail.com>
The cipher access restriction queries (direct collection access, group
collection access, and full access via groups) never checked the
organization membership status. Since users_collections and groups_users
rows are kept when a membership is revoked, revoked (and not yet
confirmed) members kept read, write, delete, attachment and
collection-move access to org ciphers via the direct-by-UUID endpoints.
Require a confirmed membership in the cipher's organization in all
three queries, matching the behavior of the sync queries.
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
Introduced in 2026.4.1 Mobile releases (Android and iOS), enables use of
device camera to autofill a card type item.
N.B. This feature relies on Google ML Kit. F-Droid policy disallows
Google ML Kit. Because of this, F-Droid builds do not ship with card
scanner feature. (See https://github.com/bitwarden/android/pull/6890)
When `archiveDate` is set to `null` it should unarchive it for that
specific user, which is what Bitwarden does.
This should fix this by checking and validating if it is `null`
Fixes#7581
Signed-off-by: BlackDex <black.dex@gmail.com>
* storage: route OpenDAL through HTTP client
OpenDAL 0.58 requires applications to provide an HTTP transport. Its
default installer creates a standalone client, bypassing Vaultwarden
DNS, redirect, proxy, timeout, and request configuration.
Build the client through the internal HTTP interface and inject it into
OpenDAL's public reqwest transport.
* http: honor block setting on redirects
Clients can disable host blocking for administrator-configured private
services. DNS resolution honors this setting, but the redirect policy
still performs config-backed host checks.
Capture the setting in the redirect policy and skip those checks when
blocking is disabled. This also avoids re-entering CONFIG when a remote
configuration request is redirected during startup.
* http: make DNS setup bootstrap-safe
Remote configuration can require an HTTP client while CONFIG is still
initializing. Building the DNS resolver currently reads
CONFIG.dns_prefer_ipv6(), so loading an S3-backed config can deadlock.
Build one resolver without consulting CONFIG. Order addresses for each
lookup using the merged setting when available, falling back to the
environment and then IPv4-first during bootstrap.
* aws: use internal HTTP client
The AWS SDK connector builds a raw reqwest client, bypassing
Vaultwarden TLS, DNS, redirect, proxy, timeout, and request setup.
Construct it through the internal HTTP client interface and retain the
standard ten-second request deadline. Permit private AWS metadata and
service endpoints by disabling non-global IP blocking.
Preserve timeout errors when adapting reqwest failures to the AWS SDK so
the runtime receives the correct connector error category.
* Added comment for the prefer IPv function
Signed-off-by: BlackDex <black.dex@gmail.com>
---------
Signed-off-by: BlackDex <black.dex@gmail.com>
Co-authored-by: BlackDex <black.dex@gmail.com>
- Update Rust to v1.98.1 which resolves a build issues with strange
outcomes
- Adjusted the DockerSettings and render_template to extract the
`rust_version` from the `rust-toolchain.toml` file. This should
prevent mismatches and forgetting to update DockerSettings.
- Updated typos in GHA and Pre-Commit
- Updated all possible crates including hickory which has several CVE's
fixed.
Signed-off-by: BlackDex <black.dex@gmail.com>
Docker only recognizes `#` as a valid comment indicator in .dockerignore files.
Using `//` causes the lines to be incorrectly parsed as glob patterns rather than comments.
While this may not cause fatal errors if no matching files exist, it is syntactically invalid and could lead to unexpected behavior. Corrected the syntax to use `#`.
The three "Username or password is incorrect" errors in
send_email_login() (email.rs) don't log the client IP or submitted
identifier, unlike the equivalent wrong-password error in
password_login() (identity.rs), which logs both via
format!("IP: {}. Username: {username}.", ip.ip).
This makes the two code paths inconsistent for the same underlying
error, and means log-based tooling that keys on the identity.rs
error's "IP: x.x.x.x" pattern can't do the same for this endpoint.
Bring email.rs's three call sites in line with identity.rs's existing
format. The two email-present branches log IP+Username (the email
submitted); the device-identifier-only branch (SSO path, no email in
scope) logs IP+Device instead of fabricating a username.
Verified: cargo build/test/clippy/fmt all pass with the sqlite feature
(matching one leg of this repo's own CI matrix), including the two
existing unit tests in this file.
Account recovery requires SMTP. When mail is off, treat the organization
reset-password auto-enroll policy as inactive so invite/accept flows are
not forced to supply a reset-password key.
Fixes#7459
`src/api/core/ciphers.rs:170` comment said "similar to the the
userDecryptionOptions" -> "similar to the userDecryptionOptions".
Comment-only.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>