Skip to content

Conversation

nikwithak
Copy link

@nikwithak nikwithak commented Sep 10, 2025

🎟️ Tracking

PM-25012

📔 Objective

Moves the deserialization of the data object into the SDK - as part of running cipher migrations, the CipherType objects will be extracted instead of being passed in from the client.

⏰ 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

@nikwithak nikwithak changed the base branch from main to vault/cipher-versioning-with-data September 10, 2025 00:11
Copy link
Contributor

github-actions bot commented Sep 10, 2025

Logo
Checkmarx One – Scan Summary & Details033de3d4-c6d3-4579-b0b9-d14ccf36f138

New Issues (5)

Checkmarx found the following issues in this Pull Request

Severity Issue Source File / Package Checkmarx Insight
CRITICAL CVE-2025-7783 Npm-axios-1.9.0
detailsRecommended version: 1.12.0
Description: Use of Insufficiently Random Values vulnerability in form-data allows HTTP Parameter Pollution (HPP). This vulnerability is associated with program...
Attack Vector: NETWORK
Attack Complexity: HIGH

ID: mUXaXNR8g3c%2B4Z2NbJ2ZDN5wRtofXR4aIcNsUZzLKAo%3D
Vulnerable Package
CRITICAL CVE-2025-7783 Npm-form-data-4.0.3
detailsRecommended version: 4.0.4
Description: Use of Insufficiently Random Values vulnerability in form-data allows HTTP Parameter Pollution (HPP). This vulnerability is associated with program...
Attack Vector: NETWORK
Attack Complexity: HIGH

ID: %2BxWcQnBS9X4Xok5ZwVX22K3TBoMdgVWw7G7X8zTMiaI%3D
Vulnerable Package
HIGH CVE-2025-58754 Npm-axios-1.9.0
detailsRecommended version: 1.12.0
Description: Axios is a promise based HTTP client for the browser and Node.js. When Axios prior to version 1.12.0 runs on Node.js and is given a URL with the "d...
Attack Vector: NETWORK
Attack Complexity: LOW

ID: wnBKSriwsdG81YaA%2BxsDp%2FW0h90sUyAa%2FX8ZdZ72IvM%3D
Vulnerable Package
LOW CVE-2025-54798 Npm-tmp-0.0.33
detailsRecommended version: 0.2.4
Description: tmp is a temporary file and directory creator for node.js. In versions prior to 0.2.4, tmp is vulnerable to an arbitrary temporary file "/" directo...
Attack Vector: LOCAL
Attack Complexity: HIGH

ID: bhZ4%2FcSXS9FK4OiNvfMXf0G18EmOPXZddRTebiFzFjU%3D
Vulnerable Package
LOW Parameter_Tampering /crates/bitwarden-uniffi/kotlin/app/src/main/java/com/bitwarden/myapplication/MainActivity.kt: 399
detailsMethod decryptVault at line 399 of /crates/bitwarden-uniffi/kotlin/app/src/main/java/com/bitwarden/myapplication/MainActivity.kt gets user input ...
ID: yimmui1dZB4vMXJbg6D%2FzeEmYZ4%3D
Attack Vector

Copy link

codecov bot commented Sep 12, 2025

Codecov Report

❌ Patch coverage is 98.12332% with 7 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (vault/cipher-versioning-with-data@3127888). Learn more about missing BASE report.

Files with missing lines Patch % Lines
crates/bitwarden-vault/src/error.rs 0.00% 7 Missing ⚠️
Additional details and impacted files
@@                         Coverage Diff                          @@
##             vault/cipher-versioning-with-data     #433   +/-   ##
====================================================================
  Coverage                                     ?   74.77%           
====================================================================
  Files                                        ?      256           
  Lines                                        ?    22417           
  Branches                                     ?        0           
====================================================================
  Hits                                         ?    16762           
  Misses                                       ?     5655           
  Partials                                     ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nikwithak nikwithak changed the title WIP: Vault/pm 25012/cipher versioning data types PM-25012: Cipher versioning data types Sep 12, 2025
@nikwithak nikwithak marked this pull request as ready for review September 12, 2025 19:47
@nikwithak nikwithak requested review from a team as code owners September 12, 2025 19:47
.unwrap_or_default()
}

/// Extracts and sets the CipherType-specific fields from the opaque `data` field.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add some more documentation here ?

/// Extracts and sets the CipherType-specific fields from the opaque `data` field.
pub(crate) fn populate_cipher_types(&mut self) {
let Ok(data) =
serde_json::from_str::<serde_json::Value>(self.data.as_deref().unwrap_or("{}"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ looks like we are doing a double deserialization. Would it be better if we did this directly on the target type

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to the fact that we're doing from_str here, and from_value below?

Since we're only worried about the CipherType deserializations in this function, I think I can do away with the from_str call on this line, and only deserialize inside the match (with from_str instead of from_value).

However it sounds like I may need to refactor this anyway - if we need to keep #[deny_unknown_fields] like called out below, then we can't use serde to deserialize and I'll need to manually extract each of the values from data here - see discussion below.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're only worried about the CipherType deserializations in this function, I think I can do away with the from_str call on this line, and only deserialize inside the match (with from_str instead of from_value).

Yeah this is what I am referring to

Comment on lines 468 to 472
crate::CipherType::Login => self.login = serde_json::from_value(data).ok(),
crate::CipherType::SecureNote => self.secure_note = serde_json::from_value(data).ok(),
crate::CipherType::Card => self.card = serde_json::from_value(data).ok(),
crate::CipherType::Identity => self.identity = serde_json::from_value(data).ok(),
crate::CipherType::SshKey => self.ssh_key = serde_json::from_value(data).ok(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ what happens if deserialization fails?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the deserialization fails, then we set the value to None. The cases I can think of where serialization fails are that data doesn't contain the required values for that CipherType.

Is it preferable to fail entirely and return an error in that case? It would mean that the data stored in the cipher's.data is inconsistent with the schema we've defined.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbubemismith I added error handling - I added some additional error types to the existing VaultParseError and CipherError types in the new revision to handle these cases.

use crate::{cipher::cipher::CopyableCipherFields, Cipher, VaultParseError};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't remove the deny_unknown_fields

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we always want deny_unknown_fields to keep things in sync

What are we trying to keep in sync - is it that we don't get additional data from the server that we don't expect?

To me that makes sense if we need to make sure that the server isn't giving us additional data that we aren't expecting. But with this change, we are no longer using the server response for these fields, and are instead extracting it ourselves from the data field on the client-side - with that change, these values simply become windowed views into the datafield, and I don't think we are gaining value from rejecting unknown fields anymore.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I synced with @gbubemismith offline on this, and right now we agreed that there's no need to keep deny_unknown_fields

@gbubemismith
Copy link
Contributor

@nikwithak Nice work so far. I think we want to target the vault/feature/cipher-versioning branch,

@nikwithak nikwithak changed the base branch from vault/cipher-versioning-with-data to vault/feature/cipher-versioning September 17, 2025 23:21
@nikwithak nikwithak changed the base branch from vault/feature/cipher-versioning to vault/cipher-versioning-with-data September 17, 2025 23:22
@nikwithak
Copy link
Author

@gbubemismith

I think we want to target the vault/feature/cipher-versioning branch,

I changed the target to vault/feature/cipher-versioning, but changed it back since it cluttered the diff with all of the API changes from the current target. Do you plant to merge vault/cipher-versioning-with-data (which has the generated API code) into the feature branch, or should I nix those commits from my branch entirely? This change is dependent on the .data field added by that branch.

Copy link

@gbubemismith
Copy link
Contributor

@gbubemismith

I think we want to target the vault/feature/cipher-versioning branch,

I changed the target to vault/feature/cipher-versioning, but changed it back since it cluttered the diff with all of the API changes from the current target. Do you plant to merge vault/cipher-versioning-with-data (which has the generated API code) into the feature branch, or should I nix those commits from my branch entirely? This change is dependent on the .data field added by that branch.

I have a PR that has the api generated code, I can merge mine first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants