Wallet: keep daemon credentials scoped to each connection
What changed, and why it matters
This commit changes how the Monero GUI wallet stores and uses login credentials for remote nodes (servers that help the wallet talk to the Monero network). Previously, the wallet kept daemon username/password as persistent wallet-level settings. Now those credentials are passed fresh each time a connection is initialized, so they are scoped to that specific connection instead of lingering on the wallet object. This is a defensive cleanup that reduces the risk of credentials being reused for the wrong node or leaking across connections, but the commit message does not frame it as a security fix.
Treat as a hardening/defensive improvement. Review whether `m_daemonUsername`/`m_daemonPassword` members are still needed elsewhere, and verify that callers of `Wallet::init()`/`initAsync()` supply credentials correctly. No immediate incident response is indicated unless independent research shows this pattern was exploitable.
Security signals we found
Credential scoping change: daemon username/password no longer stored as persistent wallet state for connection reuse
Removal of setDaemonLogin() call from QML remote-node selection path
Daemon credentials now captured per-init and passed directly to underlying wallet implementation
Potential reduction in cross-connection credential confusion or reuse
No explicit security framing in commit message or diff
Evidence from the diff
The patch removes setDaemonLogin() and setTrustedDaemon() calls from main.qml’s applyRemoteNode() and instead passes daemonUsername and daemonPassword directly into Wallet::init() and Wallet::initAsync(). The async lambda captures copies of m_daemonUsername/m_daemonPassword at init time, and Wallet::init() forwards them to m_walletImpl->init(). This prevents stale or globally-scoped daemon credentials from being reused across different remote-node connections.
Changed components
src/libwalletqt/Wallet.cppsrc/libwalletqt/Wallet.hmain.qmlInspect captured patch +7 / −6
### main.qml
@@ -1605,11 +1605,8 @@ ApplicationWindow {
function applyRemoteNode(index) {
selected = index;
- const remoteNode = currentRemoteNode();
persistentSettings.useRemoteNode = true;
if (currentWallet) {
- currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
- currentWallet.setTrustedDaemon(remoteNode.trusted);
appWindow.connectRemoteNode();
}
}
### src/libwalletqt/Wallet.cpp
@@ -239,7 +239,7 @@ void Wallet::storeAsync(const QJSValue &callback, const QString &path /* = "" */
}
}
-bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight, const QString& proxyAddress)
+bool Wallet::init(const QString &daemonAddress, const QString &daemonUsername, const QString &daemonPassword, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight, const QString& proxyAddress)
{
qDebug() << "init non async";
if (isRecovering){
@@ -257,7 +257,7 @@ bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 uppe
{
QMutexLocker locker(&m_proxyMutex);
- if (!m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), false, false, proxyAddress.toStdString()))
+ if (!m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, daemonUsername.toStdString(), daemonPassword.toStdString(), false, false, proxyAddress.toStdString()))
{
return false;
}
@@ -290,9 +290,11 @@ void Wallet::initAsync(
qDebug() << "initAsync: " + daemonAddress;
m_initializing = true;
pauseRefresh();
- const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress] {
+ const auto future = m_scheduler.run([this, daemonAddress, daemonUsername = m_daemonUsername, daemonPassword = m_daemonPassword, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress] {
m_initialized = init(
daemonAddress,
+ daemonUsername,
+ daemonPassword,
trustedDaemon,
upperTransactionLimit,
isRecovering,
### src/libwalletqt/Wallet.h
@@ -432,6 +432,8 @@ class Wallet : public QObject, public PassprasePrompter
//! initializes wallet
bool init(
const QString &daemonAddress,
+ const QString &daemonUsername,
+ const QString &daemonPassword,
bool trustedDaemon,
quint64 upperTransactionLimit,
bool isRecovering,Why this scored 34/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.