fix(mwc): clear stale wallet-handle key in db v15->v16 migration
What changed, and why it matters
This commit fixes a database migration for Mimblewimblecoin (MWC) wallets in Stack Wallet. Older versions left behind a stale 'wallet handle' key in secure storage. The patch moves cleanup of that stale key from normal wallet startup into a one-time database upgrade routine, so it is reliably cleared for all users upgrading from older builds. A leftover wallet handle could potentially be reused or leaked across wallet instances, which is a security hygiene issue, though the commit itself does not describe an active exploit.
Treat as a security-hygiene fix. Verify that the migration correctly identifies all MWC wallets and that deleting the stale key does not interfere with active wallet sessions. Consider whether any other stale secure-storage keys or cached handles need similar migration cleanup. No immediate user action is required beyond updating to the fixed version.
Security signals we found
Secure-storage key deletion for stale wallet handles
Migration-time cleanup of sensitive MWC wallet state
Removal of runtime deletion logic in wallet handle accessor
Potential information disclosure or state confusion from stale handles
Evidence from the diff
The change modifies the v15→v16 database migration in lib/db/db_version_migration.dart to enumerate all MWC wallets and delete the secure-storage key ‘${walletId}_wallet’. It also removes the same deletion call from MimblewimblecoinWallet._getWalletHandle(), where it was previously performed at runtime. The migration now ensures stale handles are cleared once during upgrade rather than relying on runtime cleanup. The commit message frames this as a fix but does not disclose a specific vulnerability or credit an external reporter.
Changed components
lib/db/db_version_migration.dartlib/wallets/wallet/impl/mimblewimblecoin_wallet.dartMWC wallet secure storage keysInspect captured patch +14 / −5
diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart
index 8b56d4e..2df1213 100644
--- a/lib/db/db_version_migration.dart
+++ b/lib/db/db_version_migration.dart
@@ -374,8 +374,20 @@ class DbVersionMigrator with WalletDB {
return await migrate(15, secureStore: secureStore);
case 15:
- // No-op: nodeApiSecret field added to NodeModel (Hive field 15).
- // Existing nodes read null; updateDefaults() backfills from defaultNode.
+ // Clear stale MWC wallet handles from older builds.
+ await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
+ final mwcMigrationWalletsService = WalletsService();
+ final mwcMigrationWalletNames =
+ await mwcMigrationWalletsService.walletNames;
+ final mwcIdentifier = Mimblewimblecoin(
+ CryptoCurrencyNetwork.main,
+ ).identifier;
+ for (final walletId in mwcMigrationWalletNames.keys) {
+ if (mwcMigrationWalletNames[walletId]!.coinIdentifier ==
+ mwcIdentifier) {
+ await secureStore.delete(key: '${walletId}_wallet');
+ }
+ }
// update version
await DB.instance.put<dynamic>(
diff --git a/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart b/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
index a5f7458..db8f2c8 100644
--- a/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
+++ b/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
@@ -101,9 +101,6 @@ class MimblewimblecoinWallet extends Bip39Wallet {
final cached = _walletHandle;
if (cached != null && cached.isNotEmpty) return cached;
- // Drop stale pointer left by pre-instance-var builds.
- await secureStorageInterface.delete(key: '${walletId}_wallet');
-
final config = await _getRealConfig();
if (!_mwcLogsInitialized) {
try {
Why this scored 57/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.