wizard: check wallet file directory is writeable
What changed, and why it matters
This commit adds a simple user-facing check in the Monero wallet setup wizard: before creating a wallet, the app now verifies that the chosen folder exists and can be written to. Previously, the wizard only checked whether a location was selected, not whether it was usable. This is a defensive hardening fix that prevents user confusion and possible failed wallet creation, rather than a fix for an active attack.
Treat as a minor hardening improvement. No urgent action required; ensure downstream builds include this change and consider whether additional checks (e.g., atomic test-write, path canonicalization) are warranted for untrusted environments.
Security signals we found
Input validation hardening for filesystem path
User-facing error message added for non-writable wallet directory
No cryptographic or network changes
Evidence from the diff
The patch exposes a new Q_INVOKABLE OSHelper::isWritableDirectory() method (QFileInfo::exists/isDir/isWritable) and calls it from WizardWalletInput.qml’s wallet-location validator. It rejects wallet creation when the directory is missing or read-only. This is a local, UI-level guard; it does not address race conditions, symlink attacks, or adversarial path selection by other processes.
Changed components
Monero GUI wallet creation wizardsrc/main/oshelper.cpp / oshelper.hwizard/WizardWalletInput.qmlInspect captured patch +11 / −0
diff --git a/src/main/oshelper.cpp b/src/main/oshelper.cpp
index 2ca0e40..cb9aca7 100644
--- a/src/main/oshelper.cpp
+++ b/src/main/oshelper.cpp
@@ -248,6 +248,12 @@ QString OSHelper::temporaryPath() const
return QDir::tempPath();
}
+bool OSHelper::isWritableDirectory(const QString &path) const
+{
+ const QFileInfo info(path);
+ return info.exists() && info.isDir() && info.isWritable();
+}
+
QString OSHelper::randomPassword(int numBytes) const
{
numBytes = qBound(16, numBytes, 128);
diff --git a/src/main/oshelper.h b/src/main/oshelper.h
index 1c3aeb7..b6e98d3 100644
--- a/src/main/oshelper.h
+++ b/src/main/oshelper.h
@@ -51,6 +51,7 @@ public:
Q_INVOKABLE QString openSaveFileDialog(const QString &title, const QString &folder, const QString &filename) const;
Q_INVOKABLE QString temporaryFilename() const;
Q_INVOKABLE QString temporaryPath() const;
+ Q_INVOKABLE bool isWritableDirectory(const QString &path) const;
Q_INVOKABLE QString randomPassword(int numBytes = 32) const;
Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const;
Q_INVOKABLE bool isCapsLock() const;
diff --git a/wizard/WizardWalletInput.qml b/wizard/WizardWalletInput.qml
index 882145a..2c12d5c 100644
--- a/wizard/WizardWalletInput.qml
+++ b/wizard/WizardWalletInput.qml
@@ -154,6 +154,10 @@ GridLayout {
errorMessageWalletLocation.text = qsTr("Wallet location is empty") + translationManager.emptyString;
return false;
}
+ if (!oshelper.isWritableDirectory(walletLocation.text)) {
+ errorMessageWalletLocation.text = qsTr("Wallet location does not exist or is not writable") + translationManager.emptyString;
+ return false;
+ }
errorMessageWalletLocation.text = "";
return true;
}
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.