Sending from or exporting an HD or xprv address can use another address's key #510

Open
opened 2026-10-14 04:32:56 +02:00 by clawbot · 2 comments
Collaborator

Where

src/popup/views/confirmTx.js line 584, src/popup/views/exportPrivkey.js line 138 and findWalletFor() in src/popup/views/approval.js (lines 870-879) give getSignerForAddress() (src/shared/wallet.js lines 113-141) the address's position in wallet.addresses, and it derives the key at that position. Position and derivation index differ after either of these:

  1. Importing a recovery phrase or xprv whose used addresses have a gap: scanForAddresses() (src/shared/balances.js) keeps only the used ones.
  2. Removing an address that is not the last (src/shared/walletDelete.js line 123).

What happens

On next (8e52528), release build, Chrome, local chain with chain id 11155111:

  • Imported a phrase with indices 0, 1, 2 and 4 funded. Address 4 is 0x0a03aeaEF271c3fB6fF857911ebcd3A832F7F5Bc. Export Private Key returned the key of 0x2F68524B027e5C5Aa6752ad04fC4D480B5483694 (index 3). Sending 0.5 from Address 4: the confirmation screen showed From 0x0a03…F5Bc; the mined transaction came from 0x2F68…3694, which the wallet does not list.
  • Removed Address 2 of three; the address now listed second exported the removed address's key.

Site signatures and transactions take the same path.

What should happen

Signing and export use the shown address's own key (README: ConfirmTx From; ExportPrivKey "derives this address's key").

Severity: critical

Definition of done

  • Send, site transaction, site signature and key export derive the key at the address's own derivation index.
  • The derived address is compared with the shown address before signing or revealing, and a mismatch is refused.
  • Tests cover an import scan with a gap and removing a middle address.

Model: opus-5-5

## Where `src/popup/views/confirmTx.js` line 584, `src/popup/views/exportPrivkey.js` line 138 and `findWalletFor()` in `src/popup/views/approval.js` (lines 870-879) give `getSignerForAddress()` (`src/shared/wallet.js` lines 113-141) the address's position in `wallet.addresses`, and it derives the key at that position. Position and derivation index differ after either of these: 1. Importing a recovery phrase or `xprv` whose used addresses have a gap: `scanForAddresses()` (`src/shared/balances.js`) keeps only the used ones. 2. Removing an address that is not the last (`src/shared/walletDelete.js` line 123). ## What happens On `next` (8e52528), release build, Chrome, local chain with chain id 11155111: - Imported a phrase with indices 0, 1, 2 and 4 funded. Address 4 is `0x0a03aeaEF271c3fB6fF857911ebcd3A832F7F5Bc`. Export Private Key returned the key of `0x2F68524B027e5C5Aa6752ad04fC4D480B5483694` (index 3). Sending 0.5 from Address 4: the confirmation screen showed From `0x0a03…F5Bc`; the mined transaction came from `0x2F68…3694`, which the wallet does not list. - Removed Address 2 of three; the address now listed second exported the removed address's key. Site signatures and transactions take the same path. ## What should happen Signing and export use the shown address's own key (README: ConfirmTx From; ExportPrivKey "derives this address's key"). Severity: critical ## Definition of done - [ ] Send, site transaction, site signature and key export derive the key at the address's own derivation index. - [ ] The derived address is compared with the shown address before signing or revealing, and a mismatch is refused. - [ ] Tests cover an import scan with a gap and removing a middle address. Model: opus-5-5
clawbot self-assigned this 2026-10-14 04:32:56 +02:00
Author
Collaborator

Plan: every stored address carries the derivation index it was made at (set by the import scan, by adding an address, and at wallet creation). Send, site transactions, site signatures and key export derive the key at that stored index, never at the address's position in the list, and before signing or revealing they compare the derived address with the shown one and refuse a mismatch with a full sentence. README.md's Data Model section names the new field. Tests cover an import scan with a gap and removing a middle address, for send, site signature and export.

Model: opus-5-5

Plan: every stored address carries the derivation index it was made at (set by the import scan, by adding an address, and at wallet creation). Send, site transactions, site signatures and key export derive the key at that stored index, never at the address's position in the list, and before signing or revealing they compare the derived address with the shown one and refuse a mismatch with a full sentence. `README.md`'s Data Model section names the new field. Tests cover an import scan with a gap and removing a middle address, for send, site signature and export. Model: opus-5-5
clawbot added the critical label 2026-10-14 04:49:10 +02:00
Author
Collaborator

Built as planned above in #536. Two additions: the address check also covers private-key wallets, and the export screen now reports a refused key as such instead of as a wrong password.

Model: opus-5-5

Built as planned above in https://git.eeqj.de/sneak/AutistMask/pulls/536. Two additions: the address check also covers private-key wallets, and the export screen now reports a refused key as such instead of as a wrong password. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#510