fix(mwc): discard stale wallet handle from previous process
What changed, and why it matters
This fix prevents the Mimblewimblecoin wallet from reusing a stale wallet handle left over from a previous app launch. The old handle is a raw memory pointer stored in secure storage; using it after the app restarts would crash the app. The patch now deletes any leftover pointer unless it was created by the currently running app process, then opens the wallet fresh.
Review whether any other wallet implementations persist raw native pointers in secure storage or shared preferences and apply the same process-scoped tracking pattern. Consider adding a process-unique nonce or invalidating stored handles on app startup as a defense-in-depth measure.
Security signals we found
Use-after-free / dangling pointer from persisted raw pointer
Cross-process pointer reuse via secure storage
SIGSEGV crash on FFI dereference
Fix deletes stale handle and re-opens wallet safely
Evidence from the diff
The MimblewimblecoinWallet class was reading a serialized Rust pointer (u64 wallet handle) named ${walletId}_wallet from secure storage and returning it as a live handle. Because libsecret persists this value across process launches, the handle became a dangling pointer after the app restarted. Subsequent FFI calls such as scanOutputs would dereference it and cause a SIGSEGV. The patch introduces a static in-process Set, _openedInProcess, to track which wallet handles were created in the current process. _ensureWalletOpen() now deletes the stored key if the wallet was not opened in this process, then calls the Rust openWallet API and records the new handle.
Changed components
lib/wallets/wallet/impl/mimblewimblecoin_wallet.dartMWC Rust FFI wallet handle managementsecure storage interface (libsecret-backed)Inspect captured patch +24 / −4
diff --git a/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart b/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
index 58aedff..a3f0c7e 100644
--- a/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
+++ b/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
@@ -47,6 +47,14 @@ class MimblewimblecoinWallet extends Bip39Wallet {
static bool _mwcLogsInitialized = false;
+ /// Tracks wallets that have been openWallet'd in *this* process. The
+ /// `${walletId}_wallet` value in secure storage is a serialized Rust
+ /// pointer (u64): it persists across launches via libsecret but only
+ /// dereferences safely inside the process that wrote it. Anything in
+ /// secure storage from a previous process is a dangling pointer that
+ /// will SIGSEGV the host on FFI use.
+ static final Set<String> _openedInProcess = <String>{};
+
double highestPercent = 0;
Future<double> get getSyncPercent async {
final int lastScannedBlock =
@@ -99,10 +107,21 @@ class MimblewimblecoinWallet extends Bip39Wallet {
Future<String> _ensureWalletOpen() async {
return await _walletOpenMutex.protect(() async {
- final existing = await secureStorageInterface.read(
- key: '${walletId}_wallet',
- );
- if (existing != null && existing.isNotEmpty) return existing;
+ if (_openedInProcess.contains(walletId)) {
+ // We opened this wallet earlier in *this* process; secure storage
+ // holds the live handle.
+ final existing = await secureStorageInterface.read(
+ key: '${walletId}_wallet',
+ );
+ if (existing != null && existing.isNotEmpty) return existing;
+ } else {
+ // Whatever is in secure storage is a serialized Rust pointer from a
+ // previous process. Dereferencing it in this process crashes the
+ // host on the next FFI call (e.g. scanOutputs). Drop it so callers
+ // that read `${walletId}_wallet` directly pick up the fresh handle
+ // we're about to write.
+ await secureStorageInterface.delete(key: '${walletId}_wallet');
+ }
final config = await _getRealConfig();
// Initialize MWC's own Rust logger once per process so trace-level
@@ -133,6 +152,7 @@ class MimblewimblecoinWallet extends Bip39Wallet {
key: '${walletId}_wallet',
value: opened,
);
+ _openedInProcess.add(walletId);
return opened;
});
}
Why this scored 60/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.