feat: handle `label` restore field from cupcake (#2551)
What changed, and why it matters
This commit adds support for a 'label' field when restoring a wallet from a backup or QR code created by another app called Cupcake. It simply copies that label into the wallet name fields during restore. There is no obvious security bug here; it is a small feature addition.
No immediate security action is required. As a defensive measure, the project should validate/sanitize the imported 'label' value (length limits, disallow control characters, trim whitespace) before using it as a wallet name, and ensure downstream storage does not interpret it as markup or a file path.
Security signals we found
New user-controlled string parsed from JSON/QR is passed into UI text controllers without visible sanitization
No output encoding or length limits shown in the changed code
Restore path handles sensitive wallet material (address, view key, spend key, private key, height), though the label field itself does not touch those values
Evidence from the diff
The change extends RestoredWallet to carry an optional name/label parsed from JSON/QR input under the key ‘label’, and pre-fills two UI text controllers (nameController and nameTextEditingController) with that value when restoring from keys. The parsing is guarded by a try/catch and the field is nullable. No validation, sanitization, or escaping of the label is visible in the diff, but the value is only used as initial text in TextEditingControllers.
Changed components
lib/src/screens/restore/wallet_restore_from_keys_form.dartlib/view_model/restore/restore_wallet.dartWallet restore-from-keys flowCupcake wallet restore integrationInspect captured patch +10 / −2
diff --git a/lib/src/screens/restore/wallet_restore_from_keys_form.dart b/lib/src/screens/restore/wallet_restore_from_keys_form.dart
index 5713ad7d..8ab0f021 100644
--- a/lib/src/screens/restore/wallet_restore_from_keys_form.dart
+++ b/lib/src/screens/restore/wallet_restore_from_keys_form.dart
@@ -44,7 +44,9 @@ class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> {
{required bool displayWalletPassword, RestoredWallet? restoredWallet})
: formKey = GlobalKey<FormState>(),
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
- nameController = TextEditingController(),
+ nameController = restoredWallet != null
+ ? TextEditingController(text: restoredWallet.name)
+ : TextEditingController(),
addressController = restoredWallet != null
? TextEditingController(text: restoredWallet.address)
: TextEditingController(),
@@ -57,7 +59,9 @@ class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> {
privateKeyController = restoredWallet != null
? TextEditingController(text: restoredWallet.privateKey)
: TextEditingController(),
- nameTextEditingController = TextEditingController(),
+ nameTextEditingController = restoredWallet != null
+ ? TextEditingController(text: restoredWallet.name)
+ : TextEditingController(),
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
repeatedPasswordTextEditingController =
displayWalletPassword ? TextEditingController() : null;
diff --git a/lib/view_model/restore/restore_wallet.dart b/lib/view_model/restore/restore_wallet.dart
index 1ca8dd0c..d84a96d5 100644
--- a/lib/view_model/restore/restore_wallet.dart
+++ b/lib/view_model/restore/restore_wallet.dart
@@ -9,6 +9,7 @@ class RestoredWallet {
{required this.restoreMode,
required this.type,
required this.address,
+ this.name,
this.txId,
this.spendKey,
this.viewKey,
@@ -22,6 +23,7 @@ class RestoredWallet {
final WalletRestoreMode restoreMode;
final WalletType type;
+ final String? name;
final String? address;
final String? txId;
final String? spendKey;
@@ -41,6 +43,7 @@ class RestoredWallet {
json['address'] = codeParsed["primaryAddress"];
json['view_key'] = codeParsed["privateViewKey"];
json['height'] = codeParsed["restoreHeight"].toString();
+ json['label'] = codeParsed["label"];
}
} catch (e) {
// fine, we don't care, it is only for monero anyway
@@ -51,6 +54,7 @@ class RestoredWallet {
json['view_key'] ??= json['xpub'];
final height = json['height'] as String?;
return RestoredWallet(
+ name: json['label'] as String?,
restoreMode: json['mode'] as WalletRestoreMode,
type: json['type'] as WalletType,
address: json['address'] as String?,
Why this scored 19/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.