fix: handle unexpected ViewModel in ledger connection process (#2716)
What changed, and why it matters
This commit fixes a bug in the Cake Wallet app's process for connecting Ledger hardware wallets. Previously, if the app received an unexpected type of screen data (not a LedgerViewModel), it would silently skip a safety check and still try to proceed, which could lead to a crash or undefined behavior. The fix shows an error message and stops instead. It also adds a missing Bluetooth queue error to a list of known harmless exceptions so the app doesn't wrongly report it as a bug.
Treat as a defensive hardening fix. Review whether other hardware-wallet callbacks perform similar type checks, and confirm the ignored BLE exception does not mask a real connectivity bug. No urgent security response appears required.
Security signals we found
Type confusion / unexpected ViewModel handled defensively
Missing exception handler added for BLE queue failure
UI flow now aborts instead of continuing with invalid Ledger connection object
Crash/undefined-behavior prevention in hardware wallet onboarding path
Evidence from the diff
The patch hardens two Ledger connection callbacks in on_authentication_state_change.dart and wallet_list_page.dart by adding an else branch that alerts the user and returns when ledgerVM is not a LedgerViewModel. In wallet_list_page.dart it also moves didConnect = true and Navigator.pop inside the type check, preventing state mutation/navigation on an invalid view-model. A third change adds ‘_QueuedFuture.execute (package:universal_ble/src/queue.dart:65)’ to ExceptionHandler’s ignore list, treating that BLE queue failure as a known non-fatal exception.
Changed components
lib/reactions/on_authentication_state_change.dartlib/src/screens/wallet_list/wallet_list_page.dartlib/utils/exception_handler.dartLedger hardware wallet connection flowuniversal_ble Bluetooth queue integrationInspect captured patch +19 / −5
diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart
index d7652f7..1abf40b 100644
--- a/lib/reactions/on_authentication_state_change.dart
+++ b/lib/reactions/on_authentication_state_change.dart
@@ -61,8 +61,21 @@ void startAuthenticationStateChange(
walletType: WalletType.monero,
hardwareWalletType: HardwareWalletType.ledger,
onConnectDevice: (context, ledgerVM) async {
- if (ledgerVM is LedgerViewModel)
+ if (ledgerVM is LedgerViewModel) {
monero!.setGlobalLedgerConnection(ledgerVM.connection);
+ } else {
+ await showPopUp<void>(
+ context: context,
+ builder: (context) => AlertWithOneAction(
+ alertTitle: "Unexpected Error",
+ alertContent:
+ "Unexpected Error while trying to connect to the device (UnexpectedViewModel: ${ledgerVM.toString()})",
+ buttonText: S.of(context).try_again,
+ buttonAction: Navigator.of(context).pop,
+ ),
+ );
+ return;
+ }
showPopUp<void>(
context: context,
builder: (context) => AlertWithOneAction(
diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart
index bf882a4..7343288 100644
--- a/lib/src/screens/wallet_list/wallet_list_page.dart
+++ b/lib/src/screens/wallet_list/wallet_list_page.dart
@@ -29,7 +29,6 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:cw_core/wallet_info.dart';
-import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -484,10 +483,11 @@ class WalletListBodyState extends State<WalletListBody> {
walletType: WalletType.monero,
hardwareWalletType: HardwareWalletType.ledger,
onConnectDevice: (context, ledgerVM) async {
- if (ledgerVM is LedgerViewModel)
+ if (ledgerVM is LedgerViewModel) {
monero!.setGlobalLedgerConnection(ledgerVM.connection);
- didConnect = true;
- Navigator.of(context).pop();
+ didConnect = true;
+ Navigator.of(context).pop();
+ }
},
isReconnect: true,
),
diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart
index edb5fe7..3446e48 100644
--- a/lib/utils/exception_handler.dart
+++ b/lib/utils/exception_handler.dart
@@ -293,6 +293,7 @@ class ExceptionHandler {
"FocusScopeNode was used after being disposed",
"_getDismissibleFlushbar",
+ "_QueuedFuture.execute (package:universal_ble/src/queue.dart:65)",
];
static Future<void> _addDeviceInfo(File file) async {
Why this scored 29/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.