From 12c20f7484fdd7345721165dbdb29a9fef3ca7a9 Mon Sep 17 00:00:00 2001 From: 0xjjjjjj <0xjjjjjj@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:27:20 -0700 Subject: [PATCH] Strip null values from optional Login cipher fields Some Login ciphers stored in Vaultwarden have explicit `null` values for optional fields (e.g. `totp`, `passwordRevisionDate`, `username`, `uris`) rather than the field being absent. Upstream Bitwarden's server serializes these with `skip_serializing_if = "Option::is_none"` so the fields are always absent when unset, never `null`. The 2026.5+ Bitwarden clients (using the new sdk-internal WASM SDK) route JS `null` values into `EncString::deserialize` instead of short-circuiting `Option` to `None`, and panic with `invalid type: unit value, expected a valid string`. Serde aborts on the first failure, so one bad cipher causes the entire vault to fail to load. Match upstream's shape by stripping explicit `null` values from the affected keys before emit. The legacy `uri` field (set unconditionally to `Value::Null` at line 261 for old mobile client compat) is deliberately not stripped. Refs: #7361, bitwarden/clients#21135 --- src/db/models/cipher.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index 2fa6260a..9dc596b1 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -280,6 +280,23 @@ impl Cipher { if let Some(pw_revision) = type_data_json["passwordRevisionDate"].as_str() { type_data_json["passwordRevisionDate"] = json!(validate_and_format_date(pw_revision)); } + + // Strip `null`s from optional Login fields — newer WASM clients panic (see #7361). + if let Value::Object(ref mut map) = type_data_json { + for key in [ + "password", + "username", + "totp", + "autofillOnPageLoad", + "fido2Credentials", + "passwordRevisionDate", + "uris", + ] { + if map.get(key).is_some_and(Value::is_null) { + map.remove(key); + } + } + } } // Fix secure note issues when data is invalid