Skip to content

FIX: dead mnemonic validation on wallet import - #145

Merged
theanmolsharma merged 3 commits into
CypherCommons:masterfrom
chaitika:fix/import-wallet-mnemonic-validation
Sep 1, 2026
Merged

FIX: dead mnemonic validation on wallet import#145
theanmolsharma merged 3 commits into
CypherCommons:masterfrom
chaitika:fix/import-wallet-mnemonic-validation

Conversation

@chaitika

Copy link
Copy Markdown
Contributor

The finding

ImportWallet.tsx:146 was supposed to reject invalid seed phrases:

wallet.setSecret(text.trim());
...
if (!wallet.validateMnemonic() && !wallet.getSecret()) {
  // show "invalid mnemonic" error
}

setSecret() on line 142 runs first and always leaves the wallet's secret non-empty (worst case, a garbage input like "!!!" still normalizes to a single space). So by the time the if runs, wallet.getSecret() is never empty, !wallet.getSecret() is always false, and anything && false is always false. The result: validateMnemonic() is called, but its answer is never actually acted on. The error branch is unreachable.

Implications

The BIP39 checksum is the only thing that catches a mistyped or garbage recovery phrase before it's used. Downstream, bip39.mnemonicToSeedSync doesn't validate anything either — it will grind any string into a seed via PBKDF2. And addAndSaveWallet / addWallet (StorageProvider.tsx) have no validation of their own.

So the full path from broken input to "success" is unguarded end to end: type "asdf" into Import Wallet, and the app derives a wallet from it, saves it, fires a success haptic, shows "Wallet imported successfully," and lands you on the wallet list with a 0 balance. Nothing tells you the phrase you typed wasn't valid. If this happens on a real restore (a mistyped word from a backup), the user has no way to know their actual funds weren't recovered — they're looking at a different, unrelated wallet that just happens to be empty.

The fix

Delete the dead clause. The condition now does what it always should have:

if (!wallet.validateMnemonic()) {

Invalid phrases are now rejected with the existing error_invalid_mnemonic alert before a wallet is ever created.

Testing

  • Added tests/unit/import-wallet-mnemonic-validation.test.tsx: renders ImportWallet end to end and asserts a garbage string is rejected (alert shown, addAndSaveWallet never called), while a real BIP39 phrase still imports and navigates normally.
  • Verified the test actually catches the regression: it fails against the old && !wallet.getSecret() condition and passes with the fix.
  • npm run lint && npm run tslint && npm run unit all pass.

Copilot AI lite review requested due to automatic review settings August 21, 2026 11:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread tests/unit/importWallet.test.tsx
Comment thread screen/wallets/ImportWallet.tsx
Comment thread screen/wallets/ImportWallet.tsx
Comment thread screen/wallets/ImportWallet.tsx
Comment thread screen/wallets/ImportWallet.tsx Outdated
Comment thread screen/wallets/ImportWallet.tsx
Comment thread tests/unit/importWallet.test.tsx
Comment thread tests/unit/importWallet.test.tsx
Comment thread tests/unit/import-wallet-mnemonic-validation.test.tsx Outdated
Comment thread tests/unit/import-wallet-mnemonic-validation.test.tsx Outdated
Comment thread tests/unit/import-wallet-mnemonic-validation.test.tsx Outdated
Copilot AI review requested due to automatic review settings August 31, 2026 11:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

wallet.getSecret() is always non-empty after setSecret() runs on the
line above, so `!wallet.getSecret()` in the && condition was always
false and validateMnemonic()'s result was never checked. Any garbage
string passed silently and created an unrecoverable wallet.
Renders ImportWallet end to end and asserts that a garbage string is
rejected with the invalid-mnemonic alert (and never reaches
addAndSaveWallet), while a real BIP39 phrase still imports normally.
Confirmed this test fails against the pre-fix condition and passes
against the fix.
@chaitika
chaitika force-pushed the fix/import-wallet-mnemonic-validation branch from 97afb4e to c7e0011 Compare September 1, 2026 06:46
Copilot AI review requested due to automatic review settings September 1, 2026 06:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Drop the now-false "or private key" copy from the mnemonic error
strings, remove redundant setIsLoading(false) calls made unreachable
by the finally block, close a second dead branch (unreachable
'network' birth-height error) with a compiler-checked message map,
and tighten the regression test (diagnostics, exact-count assertion,
rename to match repo convention, assert saved wallet state).
Copilot AI review requested due to automatic review settings September 1, 2026 06:50
@chaitika
chaitika force-pushed the fix/import-wallet-mnemonic-validation branch from c7e0011 to be39af8 Compare September 1, 2026 06:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@theanmolsharma
theanmolsharma merged commit 1e016d1 into CypherCommons:master Sep 1, 2026
4 checks passed
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.

4 participants