fix: wipe the exported private key from the DOM on leaving the screen (closes #221)
All checks were successful
check / check (push) Successful in 35s
All checks were successful
check / check (push) Successful in 35s
The export screen registered no view-leave cleanup, so leaving it by any route other than its own Back button — the settings gear, for instance — left the decrypted private key in #export-privkey-value inside the hidden view for the rest of the popup's life. The reveal path had the same post-await hole the recovery phrase screen had: the write landed after the wipe, with nothing scheduled to wipe it again. The screen moves out of addressDetail.js into its own module shaped like showPhrase.js: onViewLeave() cleanup that wipes the value node, the password input and the closure state, and a revealGeneration liveness guard captured before the decrypt. The guard sits in front of the key derivation, so a decrypt that resolves after the screen was left does not even derive the key. The audit for the same bug class covered every other screen holding secret material in the DOM. AddWallet (a generated or pasted recovery phrase, an imported private key or extended private key, and the password) and the password inputs on ConfirmTx, DeleteWallet, ApproveTx and ApproveSign were all cleared on entry only, so each survived in its hidden view after the screen navigated on. All five now register the same cleanup. None of them writes a secret after an await, so none needs a generation guard. The load-bearing test leaves the screen mid-decrypt and asserts the key never lands in the DOM, and that it still does not land once the user has returned to the screen — which the generation counter catches and a current-view check alone would not.
This commit is contained in:
21
README.md
21
README.md
@@ -486,6 +486,14 @@ ExportPrivKey and ShowRecoveryPhrase — are deliberately absent from that list,
|
||||
so the popup can never reopen onto one of them with no password prompt in front
|
||||
of it.
|
||||
|
||||
Every screen that holds secret material in the page registers a cleanup with
|
||||
`onViewLeave()` (`src/popup/views/helpers.js`), which `showView()` runs on every
|
||||
exit from that screen rather than only on its "Back" button, so nothing secret
|
||||
survives in a hidden view once the user has navigated away by any route. That
|
||||
covers the revealed private key and recovery phrase, the recovery phrase,
|
||||
private key or extended private key entered on AddWallet, and the password typed
|
||||
on ConfirmTx, DeleteWallet, ApproveTx and ApproveSign.
|
||||
|
||||
#### Welcome (`welcome`)
|
||||
|
||||
- **When**: No wallets exist yet (`state.hasWallet` is false). This is the root
|
||||
@@ -596,10 +604,15 @@ of it.
|
||||
- "Reveal" (correct password) → decrypts the wallet secret, derives this
|
||||
address's key, hides the password input and shows the key (no screen
|
||||
change)
|
||||
- "Reveal" (wrong password) → "Wrong password." on the error line, nothing
|
||||
revealed
|
||||
- "Back" → clears the key and password from the DOM, then → previous screen
|
||||
(AddressDetail)
|
||||
- "Reveal" (wrong password) → full-sentence error on the error line, nothing
|
||||
revealed (no screen change)
|
||||
- "Back" → previous screen (AddressDetail)
|
||||
- **Secret handling**: nothing is decrypted, no key is derived, and nothing is
|
||||
written into the page until the password is accepted; the key is never stored
|
||||
in state, and it is wiped from the page whenever the screen is left by any
|
||||
route, including the Settings gear. A decrypt still running when the screen is
|
||||
left is discarded rather than written. The screen is not restorable, so
|
||||
reopening the popup lands on Home rather than back on the key.
|
||||
|
||||
#### AddressToken (`address-token`)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user