Skip to content

fix(security): sanitize vault options, bound PBKDF2 iterations, scrubpassword buffers, and guard vault parsing - #74

Open
mozluk wants to merge 1 commit into
MetaMask:mainfrom
mozluk:mozluk-patch-1
Open

mozluk wants to merge 1 commit into
MetaMask:mainfrom
mozluk:mozluk-patch-1

Conversation

@mozluk

@mozluk mozluk commented Sep 20, 2026 •

Copy link
Copy Markdown

Description

Remediates input validation, resource exhaustion, and memory hygiene vulnerabilities in @metamask/browser-passworder (Findings BP-1 through BP-4).

Key Changes & Security Rationale

  • Robust Key Derivation Guard (BP-1 - src/index.ts):

    • Hardened isKeyDerivationOptions: verifies isPlainObject(params) and asserts that iterations is a valid numeric value.
    • Prevents malformed vault payloads (such as {"params": null}) from passing validation and crashing on object destructuring with untyped TypeError exceptions.
  • Iteration Ceiling Bounding (BP-2 - src/index.ts):

    • Lowered MAX_PBKDF2_ITERATIONS from 10,000,000 to 3,000,000.
    • Restricts malicious vaults from triggering extreme PBKDF2 computation loops that freeze user browser threads on unlock attempts.
  • In-Memory Password Zeroization (BP-3 - src/index.ts):

    • Enforced passBuffer.fill(0) immediately following WebCrypto key derivation and on early invalid-salt rejections in keyFromPassword.
    • Ensures raw password byte representations are scrubbed from heap memory instead of persisting until garbage collection.
  • Structured Vault Parsing & Validation (BP-4 - src/index.ts):

    • Implemented parseVault(text: string) to validate that incoming ciphertext objects strictly contain required string fields (data, iv, salt).
    • Standardized JSON parsing error boundaries to prevent unhandled low-level exceptions in downstream decryption pathways.

Verification

  • Verified Playwright test suite execution across encryption and decryption flows.
  • Validated backwards compatibility with both legacy 10,000-iteration vaults and modern 900,000-iteration vaults.
  • Confirmed correct error handling when decrypting with incorrect passwords or corrupted vault JSON payloads.

Note

High Risk
Changes sit on the password vault unlock path (PBKDF2 bounds, parsing, and error semantics); regressions could block legitimate vaults or alter security behavior under malicious input.

Overview
Hardens untrusted vault and KDF input in the browser passworder decrypt/derive path without changing the public encrypt API shape.

Vault parsing: decrypt / decryptWithDetail now go through parseVault, which rejects non-JSON or malformed payloads (missing data, iv, or salt strings) with explicit "Invalid vault format" errors instead of failing deeper in the stack. isVaultUpdated safely treats bad JSON as not updated.

KDF safety: New validateKeyDerivationOptions enforces PBKDF2 only and iteration counts between 1,000 and 3,000,000 (safe integers). isKeyDerivationOptions now requires a real params object and numeric iterations so crafted metadata cannot crash on destructuring. keyFromPassword rejects salts shorter than 16 decoded bytes, validates options on every call, and zero-fills the password buffer after derive (and on early salt failure).

Compatibility & errors: Vaults without keyMetadata still unlock via explicit OLD_DERIVATION_PARAMS (10k iterations) while the keyFromPassword default is now 900k for new keys. Wrong keys still surface "Incorrect password" only from WebCrypto decrypt failure; invalid post-decrypt JSON becomes "Corrupt vault: decrypted payload is not valid JSON". importKey wraps invalid key JSON similarly.

The Playwright suite in test/index.spec.ts is unchanged aside from line shifts; existing legacy and modern fixture vault tests still cover backward compatibility.

Reviewed by Cursor Bugbot for commit 3697276. Bugbot is set up for automated code reviews on this repo. Configure here.

… password buffers, and guard vault parsing

## Description
Remediates input validation, resource exhaustion, and memory hygiene vulnerabilities in `@metamask/browser-passworder` (Findings BP-1 through BP-4).

## Key Changes & Security Rationale

* **Robust Key Derivation Guard (BP-1 - `src/index.ts`)**:
  - Hardened `isKeyDerivationOptions`: verifies `isPlainObject(params)` and asserts that `iterations` is a valid numeric value.
  - Prevents malformed vault payloads (such as `{"params": null}`) from passing validation and crashing on object destructuring with untyped `TypeError` exceptions.

* **Iteration Ceiling Bounding (BP-2 - `src/index.ts`)**:
  - Lowered `MAX_PBKDF2_ITERATIONS` from 10,000,000 to 3,000,000.
  - Restricts malicious vaults from triggering extreme PBKDF2 computation loops that freeze user browser threads on unlock attempts.

* **In-Memory Password Zeroization (BP-3 - `src/index.ts`)**:
  - Enforced `passBuffer.fill(0)` immediately following WebCrypto key derivation and on early invalid-salt rejections in `keyFromPassword`.
  - Ensures raw password byte representations are scrubbed from heap memory instead of persisting until garbage collection.

* **Structured Vault Parsing & Validation (BP-4 - `src/index.ts`)**:
  - Implemented `parseVault(text: string)` to validate that incoming ciphertext objects strictly contain required string fields (`data`, `iv`, `salt`).
  - Standardized JSON parsing error boundaries to prevent unhandled low-level exceptions in downstream decryption pathways.

## Verification
- Verified Playwright test suite execution across encryption and decryption flows.
- Validated backwards compatibility with both legacy 10,000-iteration vaults and modern 900,000-iteration vaults.
- Confirmed correct error handling when decrypting with incorrect passwords or corrupted vault JSON payloads.
@mozluk
mozluk requested a review from a team as a code owner September 20, 2026 22:30

This branch has not been deployed

No deployments
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.

1 participant