fix(mwc): write .api_secret for default node authentication
What changed, and why it matters
This commit fixes how Stack Wallet's Mimblewimblecoin (MWC) wallet connects to the default MWC node. Previously, the wallet did not write the required API secret file, so the Rust backend could not authenticate to the default node. The patch now writes a hardcoded secret to a file named .api_secret in the wallet directory when the configured node is the default one. The security concern is that the secret is embedded in the source code and stored on disk, and any app or process with access to the wallet directory can read it. However, this appears to be the intended public secret for the default node, not a private user credential.
Treat this as a configuration fix rather than a critical vulnerability. If the default-node secret must remain public, document it clearly and ensure the wallet directory has restrictive file permissions. Consider whether the secret should be fetched or configured per-node rather than hardcoded. Review whether other wallets or plugins rely on similar default secrets.
Security signals we found
Hardcoded API secret embedded in client source code
Secret written to local filesystem in wallet directory
Conditional write based on default node hostname
Deletion of secret file when non-default node is used
Authentication credential exposed in version control
Evidence from the diff
The change adds _ensureApiSecret(), which creates the wallet directory if needed and writes the hardcoded string ‘11ne3EAUtOXVKwhxm84U’ to $walletDir/.api_secret whenever the node URL contains the default host mwc713.mwc.mw. If a non-default node is used, the file is deleted if it exists. The Rust HTTPNodeClient then uses this file to authenticate to the MWC node’s API. The secret is visible in source code and written to local storage, but it matches the documented default-node authentication pattern for MWC public nodes.
Changed components
lib/wallets/wallet/impl/mimblewimblecoin_wallet.dartMWC wallet node authenticationRust HTTPNodeClient via .api_secret fileInspect captured patch +18 / −1
diff --git a/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart b/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
index dad7b36..a577b03 100644
--- a/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
+++ b/lib/wallets/wallet/impl/mimblewimblecoin_wallet.dart
@@ -582,6 +582,8 @@ class MimblewimblecoinWallet extends Bip39Wallet {
final String nodeApiAddress = uri.toString();
final walletDir = await _currentWalletDirPath();
+ await _ensureApiSecret(walletDir, nodeApiAddress);
+
final Map<String, dynamic> config = {};
config["wallet_dir"] = walletDir;
config["check_node_api_http_addr"] = nodeApiAddress;
@@ -591,6 +593,21 @@ class MimblewimblecoinWallet extends Bip39Wallet {
return stringConfig;
}
+ /// Write the node API secret to .api_secret in the wallet directory so that
+ /// the Rust HTTPNodeClient can authenticate to the MWC node.
+ Future<void> _ensureApiSecret(String walletDir, String nodeUrl) async {
+ const defaultNodeHost = 'mwc713.mwc.mw';
+ const defaultNodeSecret = '11ne3EAUtOXVKwhxm84U';
+
+ final file = File('$walletDir/.api_secret');
+ if (nodeUrl.contains(defaultNodeHost)) {
+ await Directory(walletDir).create(recursive: true);
+ await file.writeAsString(defaultNodeSecret);
+ } else if (await file.exists()) {
+ await file.delete();
+ }
+ }
+
Future<String> _currentWalletDirPath() async {
final Directory appDir = await StackFileSystem.applicationRootDirectory();
Why this scored 63/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.