wallet_rpc_server: reject --password with --wallet-dir
What changed, and why it matters
This change stops users from starting the Monero wallet RPC server with both a global wallet password and a wallet directory mode. When running with --wallet-dir, the server can manage multiple wallets, each with its own password. Supplying a single --password in that mode could have caused the password to be applied to all wallets or otherwise weaken security expectations. The patch now rejects that combination and updates shell tab-completion to reflect the restriction.
Treat as a low-to-moderate hardening fix. Operators using monero-wallet-rpc should verify startup scripts do not combine --wallet-dir with --password or --password-file. No emergency response is indicated, but the fix should be included in the next release.
Security signals we found
CLI argument combination now rejected that could have led to a single password being used across multiple wallets in --wallet-dir mode
Completion scripts updated to prevent users from accidentally selecting the incompatible combination
No cryptographic or network-layer changes; the fix is at the configuration/startup boundary
Evidence from the diff
The commit adds wallet2::has_password_option() and uses it in wallet_rpc_server.cpp to return an error if –wallet-dir is non-empty and –password was supplied. It also updates fish shell completion rules so –password/–password-file are not suggested when –wallet-dir is present and vice versa. The patch is purely a CLI argument validation hardening; it does not change RPC methods, cryptography, or wallet storage.
Changed components
src/wallet/wallet2.cppsrc/wallet/wallet2.hsrc/wallet/wallet_rpc_server.cpputils/fish/monero-wallet-rpc.fishInspect captured patch +15 / −3
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 86eba93..f8a0066 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1293,6 +1293,11 @@ bool wallet2::has_stagenet_option(const boost::program_options::variables_map& v
return command_line::get_arg(vm, options().stagenet);
}
+bool wallet2::has_password_option(const boost::program_options::variables_map& vm)
+{
+ return command_line::has_arg(vm, options().password);
+}
+
bool wallet2::has_proxy_option() const
{
return !m_proxy.empty();
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 863a4b6..34ef3e4 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -216,6 +216,7 @@ private:
static bool has_testnet_option(const boost::program_options::variables_map& vm);
static bool has_stagenet_option(const boost::program_options::variables_map& vm);
+ static bool has_password_option(const boost::program_options::variables_map& vm);
static std::string device_name_option(const boost::program_options::variables_map& vm);
static std::string device_derivation_path_option(const boost::program_options::variables_map &vm);
static void init_options(boost::program_options::options_description& desc_params);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 8239aa0..fd6735d 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -5008,6 +5008,12 @@ public:
return false;
}
+ if(!wallet_dir.empty() && tools::wallet2::has_password_option(vm))
+ {
+ LOG_ERROR(tools::wallet_rpc_server::tr("--password is not allowed in combination with --wallet-dir"));
+ return false;
+ }
+
if (!wallet_dir.empty())
{
try
diff --git a/utils/fish/monero-wallet-rpc.fish b/utils/fish/monero-wallet-rpc.fish
index fbba080..5a0de94 100644
--- a/utils/fish/monero-wallet-rpc.fish
+++ b/utils/fish/monero-wallet-rpc.fish
@@ -7,8 +7,8 @@ complete -c monero-wallet-rpc -l daemon-host -r -d "Use daemon instance at host
complete -c monero-wallet-rpc -l proxy -r -d "[<ip>:]<port> socks proxy to use for daemon connections"
complete -c monero-wallet-rpc -l trusted-daemon -d "Enable commands which rely on a trusted daemon"
complete -c monero-wallet-rpc -l untrusted-daemon -d "Disable commands which rely on a trusted daemon"
-complete -c monero-wallet-rpc -l password -r -d "Wallet password (escape/quote as needed)"
-complete -c monero-wallet-rpc -l password-file -r -F -d "Wallet password file"
+complete -c monero-wallet-rpc -l password -r -n "not __fish_seen_argument -l wallet-dir" -d "Wallet password (escape/quote as needed)"
+complete -c monero-wallet-rpc -l password-file -r -F -n "not __fish_seen_argument -l wallet-dir" -d "Wallet password file"
complete -c monero-wallet-rpc -l daemon-port -r -d "Use daemon instance at port <arg> instead of 18081. Default: 0"
complete -c monero-wallet-rpc -l daemon-login -r -d "Specify username[:password] for daemon RPC client"
complete -c monero-wallet-rpc -l daemon-ssl -x -a "enabled disabled autodetect" -d "Enable SSL on daemon RPC connections. Default: autodetect"
@@ -52,7 +52,7 @@ complete -c monero-wallet-rpc -l rpc-ssl-allow-chained -d "Allow user (via --rpc
complete -c monero-wallet-rpc -l disable-rpc-ban -d "Do not ban hosts on RPC errors"
complete -c monero-wallet-rpc -l wallet-file -r -F -d "Use wallet <arg>"
complete -c monero-wallet-rpc -l generate-from-json -r -k -a "(__fish_complete_suffix .json)" -d "Generate wallet from JSON format file"
-complete -c monero-wallet-rpc -l wallet-dir -r -a "(__fish_complete_directories)" -d "Directory for newly created wallets"
+complete -c monero-wallet-rpc -l wallet-dir -r -a "(__fish_complete_directories)" -n "not __fish_seen_argument -l password -l password-file" -d "Directory for newly created wallets"
complete -c monero-wallet-rpc -l prompt-for-password -d "Prompts for password when not provided"
complete -c monero-wallet-rpc -l detach -d "Run as daemon"
complete -c monero-wallet-rpc -l pidfile -r -F -d "File path to write the daemon's PID to (optional, requires --detach)"
Why this scored 46/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.