wallettool: Disallow creating new unnamed wallets
What changed, and why it matters
This commit tightens the bitcoin-wallet command-line tool so it can no longer create a wallet without an explicit name. Previously, the tool allowed creating an unnamed wallet in some situations, which could lead to confusion or accidental wallet files being placed in unexpected locations. The change adds clear error messages and tests to ensure the tool refuses to create unnamed wallets for both regular creation and creation from a dump file.
No immediate action required beyond normal review and testing. Users of bitcoin-wallet should ensure they always provide an explicit -wallet name when creating wallets. Consider reviewing whether any documentation or release notes mention the previous unnamed-wallet behavior.
Security signals we found
Input validation hardening: empty wallet name now rejected explicitly
Command-line argument validation extended to 'createfromdump'
Functional tests updated to assert refusal of unnamed wallet creation
Potential path/location confusion risk mitigated by requiring explicit wallet names
Evidence from the diff
The patch modifies src/wallet/wallettool.cpp and src/wallet/dump.cpp to reject empty wallet names during ‘create’ and ‘createfromdump’ commands. It also updates the command-line validation to require -wallet for ‘createfromdump’ just as it already did for ‘create’. The functional tests are updated to expect these new error messages and to remove tests that previously exercised unnamed wallet creation.
Changed components
bitcoin-wallet CLI toolsrc/wallet/wallettool.cppsrc/wallet/dump.cpptest/functional/tool_wallet.pyInspect captured patch +21 / −7
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index eb6fa0e4..f7f6554b 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -121,6 +121,11 @@ static void WalletToolReleaseWallet(CWallet* wallet)
bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
+ if (name.empty()) {
+ tfm::format(std::cerr, "Wallet name cannot be empty\n");
+ return false;
+ }
+
// Get the dumpfile
std::string dump_filename = args.GetArg("-dumpfile", "");
if (dump_filename.empty()) {
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index 3e335bc3..1ac0bbb7 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -111,7 +111,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
return false;
}
- if (command == "create" && !args.IsArgSet("-wallet")) {
+ if ((command == "create" || command == "createfromdump") && !args.IsArgSet("-wallet")) {
tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
return false;
}
@@ -119,6 +119,10 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
if (command == "create") {
+ if (name.empty()) {
+ tfm::format(std::cerr, "Wallet name cannot be empty\n");
+ return false;
+ }
DatabaseOptions options;
ReadDatabaseArgs(args, options);
options.require_create = true;
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 44ac1da9..9255b261 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -136,6 +136,7 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
self.assert_raises_tool_error('No method provided. Run `bitcoin-wallet -help` for valid methods.')
self.assert_raises_tool_error('Wallet name must be provided when creating a new wallet.', 'create')
+ self.assert_raises_tool_error('Wallet name must be provided when creating a new wallet.', 'createfromdump')
error = f"SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['CLIENT_NAME']}?"
self.assert_raises_tool_error(
error,
@@ -319,12 +320,6 @@ class ToolWalletTest(BitcoinTestFramework):
self.write_dump(dump_data, bad_sum_wallet_dump)
self.assert_raises_tool_error('Error: Checksum is not the correct size', '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
assert not (self.nodes[0].wallets_path / "badload").is_dir()
- self.assert_raises_tool_error('Error: Checksum is not the correct size', '-wallet=', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
- assert self.nodes[0].wallets_path.exists()
- assert not (self.nodes[0].wallets_path / "wallet.dat").exists()
-
- self.log.info('Checking createfromdump with an unnamed wallet')
- self.do_tool_createfromdump("", "wallet.dump")
def test_chainless_conflicts(self):
self.log.info("Test wallet tool when wallet contains conflicting transactions")
@@ -427,6 +422,15 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_raises_tool_error("Invalid parameter -descriptors", "-wallet=legacy", "-descriptors=false", "create")
assert not (self.nodes[0].wallets_path / "legacy").exists()
+ def test_no_create_unnamed(self):
+ self.log.info("Test that unnamed (default) wallets cannot be created")
+
+ self.assert_raises_tool_error("Wallet name cannot be empty", "-wallet=", "create")
+ assert not (self.nodes[0].wallets_path / "wallet.dat").exists()
+
+ self.assert_raises_tool_error("Wallet name cannot be empty", "-wallet=", "-dumpfile=wallet.dump", "createfromdump")
+ assert not (self.nodes[0].wallets_path / "wallet.dat").exists()
+
def run_test(self):
self.wallet_path = self.nodes[0].wallets_path / self.default_wallet_name / self.wallet_data_filename
self.test_invalid_tool_commands_and_args()
@@ -439,6 +443,7 @@ class ToolWalletTest(BitcoinTestFramework):
self.test_chainless_conflicts()
self.test_dump_very_large_records()
self.test_no_create_legacy()
+ self.test_no_create_unnamed()
if __name__ == '__main__':
Why this scored 36/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.