Skip to content

key restore ignores --password, so restoring a passphrase-protected mnemonic gives the wrong key #372

Closed

Description

@chukwudiikeh

Describe the bug
key restore --password <PASSPHRASE> silently ignores the passphrase. The restored xprv and fingerprint are always derived from the mnemonic alone, so a key generated with key generate --password cannot be restored with the same mnemonic and password.

The cause is in src/handlers/key.rs, RestoreKeyCommand::execute:

let xkey: ExtendedKey = (mnemonic.clone(), &self.password).0.into_extended_key()?;

.0 takes only the first element of the tuple (the Mnemonic), so self.password is discarded before into_extended_key() runs. GenerateKeyCommand uses the password correctly:

let xkey: ExtendedKey = (mnemonic.clone(), self.password.clone()).into_extended_key()?;

To Reproduce

bdk-cli key generate --password foo
# note the "mnemonic" and "xprv"

bdk-cli key restore --mnemonic "<mnemonic from above>" --password foo

Expected behavior
The restored xprv and fingerprint match the generated ones.

Actual: they differ. The result is the same as running key restore with no --password. Anyone who backs up a mnemonic plus a BIP-39 passphrase and later restores it with bdk-cli gets a different wallet, which looks empty, with no error or warning.

Build environment

  • BDK-CLI tag/commit: master @ 4dbc3e8

Additional context
Suggested fix:

let xkey: ExtendedKey = (mnemonic.clone(), self.password.clone()).into_extended_key()?;

plus an integration test in tests/integration/init.rs next to test_cli_key_restore (which never passes a password, so it doesn't catch this):

  • generate with --password foo, restore with --password foo, and assert the xprv and fingerprint match
  • restore without a password and assert the xprv differs

I'd be happy to open a PR for this.

Activity

  1. added a commit that references this issue on Nov 5, 2026
    dfaec90
  2. moved this from Todo to In Progress in BDK-CLIon Nov 5, 2026
  3. emma31-dev commented on Nov 5, 2026

    @emma31-dev

    The issue is real but implementation is wrong. you must have been thinking about MnemonicWithPassphrase from bdk_wallet::keys::bip39 but that type has no method at all as of the version of bdk_wallet used.

    let xkey: ExtendedKey = (mnemonic.clone(), self.password.clone()).into_extended_key()?;

    This wouldn't even pass cargo check. Since you are already working on it the correct implementation of this is :

    let xkey: ExtendedKey = mnemonic.clone().into_extended_key()?;
    let xprv = xkey.into_xprv(ctx.network.into()).ok_or_else(|| {
        Error::Generic("Privatekey info not found (should not happen)".to_string())
    })?;
    let xprv = if let Some(passphrase) = &self.password {
        let seed = mnemonic.to_seed(passphrase);
         Xpriv::new_master(ctx.network, &seed)?
    } else {
        xprv
    };

    Thanks for addressing this.

  4. chukwudiikeh commented on Nov 6, 2026

    @chukwudiikeh
    ContributorAuthor

    Thanks for taking a look, @emma31-dev. This does compile: cargo check passes on this branch and the new test runs in CI. MnemonicWithPassphrase is a type alias for (Mnemonic, Option<String>), and into_extended_key comes from the DerivableKey impl for it in bdk_wallet 3.1.0 (src/keys/bip39.rs). That impl calls mnemonic.to_seed(passphrase) and builds the master key, the same steps as your snippet. It's also the line GenerateKeyCommand already uses, so keeping it keeps generate and restore consistent. @emma31-dev @tvpeter @vadim-anfv please can you take a look.

  5. added a commit that references this issue on Nov 6, 2026
    5558555
  6. vadim-anfv commented on Nov 9, 2026

    @vadim-anfv
    Collaborator

    @chukwudiikeh great find! The suggested fix looks right to me. I checked the behaviour locally: the bug reproduces on master and is gone on #373.

    I will finish reviewing #373 shortly.

  7. added this to the CLI 4.1.0 milestone on Nov 9, 2026
  8. moved this from In Progress to Done in BDK-CLIon Nov 10, 2026
  9. added a commit that references this issue on Nov 10, 2026
    9ba7801
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

  • Status
    Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions