Skip to content

feat(keyring-controller): allow exportSeedPhrase with encryption key credentials#8996

Open
tanguyenvn wants to merge 3 commits into
mainfrom
feat/TO-737-export-srp-passkey
Open

feat(keyring-controller): allow exportSeedPhrase with encryption key credentials#8996
tanguyenvn wants to merge 3 commits into
mainfrom
feat/TO-737-export-srp-passkey

Conversation

@tanguyenvn
Copy link
Copy Markdown
Contributor

@tanguyenvn tanguyenvn commented Jun 4, 2026

Explanation

What is the current state of things and why does it need to change?

KeyringController.exportSeedPhrase currently accepts only a wallet password string and validates it via verifyPassword. That works for password-based SRP reveal, but passkey step-up flows need a different credential: the passkey-derived vault encryption key. The extension’s requestRevealSeedWordsWithPasskey flow retrieves that key from PasskeyController and must prove it can decrypt the vault before returning the mnemonic.

Without encryption-key support in exportSeedPhrase, passkey-based SRP reveal cannot cryptographically bind the passkey to the current vault.

What is the solution your changes offer and how does it work?

  1. exportSeedPhrase credential object — The first argument now accepts:

    • a bare string password (unchanged, backward compatible),
    • { password: string }, or
    • { encryptionKey: string }.

    When { encryptionKey } is provided, the method validates the key via the new verifyEncryptionKey helper before exporting the mnemonic.

  2. verifyEncryptionKey — New method that imports the serialized vault encryption key and attempts to decrypt the vault with decryptWithKey. Throws if the vault is missing or decryption fails (mirroring verifyPassword behavior).

  3. Tests — Added coverage for password credential objects, encryption-key success paths (with and without keyringId), and failure paths for invalid encryption keys and missing vault.

Are there any changes whose purpose might not be obvious to those unfamiliar with the domain?

  • The vault must already be unlocked before calling exportSeedPhrase; credentials are step-up re-authentication, not vault unlock.
  • In the passkey flow, WebAuthn assertion verification happens in PasskeyController.retrieveVaultKeyWithPasskey; exportSeedPhrase({ encryptionKey }) adds a second check that the retrieved key actually decrypts this vault.
  • verifyEncryptionKey is not exposed through the KeyringController messenger action list; it is used internally by exportSeedPhrase (same pattern as how verifyPassword is exposed but used as a building block).

If your primary goal was to update one package but you found you had to update another one along the way, why did you do so?

N/A — changes are scoped to @metamask/keyring-controller only. Consumer adoption is tracked separately in the extension PR.

If you had to upgrade a dependency, why did you do so?

N/A — no dependency changes.

References

  • TO-737
  • Consumer PR (metamask-extension): adds requestRevealSeedWordsWithPasskey, which calls keyringController.exportSeedPhrase({ encryptionKey: vaultKey }, keyringId)

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

High Risk
Changes how seed phrases are gated by adding encryption-key re-auth on a security-critical export path; scope is small but mistakes could weaken step-up guarantees for passkey flows.

Overview
exportSeedPhrase now accepts step-up credentials as a bare password string (unchanged), { password }, or { encryptionKey }. For encryption-key credentials it validates the key before returning the HD mnemonic; the vault must already be unlocked.

A new verifyEncryptionKey helper imports the serialized key and attempts decryptWithKey on the vault (mirroring verifyPassword for missing vault and bad keys). It is used internally by exportSeedPhrase and is not added to the messenger action list.

Docs, messenger action JSDoc, changelog, and tests cover password objects, encryption-key success/failure paths, and optional keyringId.

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

@tanguyenvn tanguyenvn requested review from a team as code owners June 4, 2026 06:19
@tanguyenvn tanguyenvn self-assigned this Jun 4, 2026
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