Files
PalladiumWallet/docs/adr/0037-derive-address-private-keys-on-reveal.md
T
davide 06d1f59c2b fix(app): derive an address private key only when revealed
Address rows and the address detail sheet no longer carry the WIF of
every listed address for the whole session. The key is derived after the
password gate and dropped when hidden, when the sheet closes or when the
wallet closes. See ADR 0037.
2026-11-03 14:10:58 +01:00

1.7 KiB

0037. Derive an address private key only when it is revealed

  • Status: Accepted
  • Area: Security
  • Recorded: 2026-11-03

Context

AddressRow carried the WIF of its address, computed for every listed address (ten rows before the first sync, every scanned address after it). The reveal gate (password prompt) controlled only display, not presence: for the whole session the WIF of every address sat in managed strings, which cannot be zeroed, inside objects bound to the UI. That does not leak by itself, and SECURITY.md already states that keys live in process memory after unlock, but it widened the exposure to a memory dump or a binding bug for no benefit.

Decision

  • AddressRow and AddressInfo hold no key. AddressRow keeps HasPrivKey (true when the account is not watch-only); AddressInfo carries the derivation coordinates (IsChange, Index).
  • The ViewModel derives the WIF in the reveal step, after the password check (RevealPrivKeyInternal), into RevealedPrivKey, which the overlay binds to.
  • RevealedPrivKey is cleared when the key is hidden, when the sheet changes or closes, and when the wallet closes.

Consequences

  • The exposure window of an address key shrinks from the whole session to the time it is shown.
  • The WIF string still cannot be zeroed; it lives until the garbage collector reclaims it. This is documented in SECURITY.md.
  • Watch-only wallets still never reveal a key (HasPrivKey is false and the derivation returns nothing).

References

  • src/App/ViewModels/MainWindowViewModel.cs
  • src/App/ViewModels/MainWindowViewModel.Receive.cs
  • tests/PalladiumWallet.Tests/App/MainWindowViewModelSecurityTests.cs