Skip to content

Commit 48fefa8

Browse files
committed
qt: Prevent re-execution of sensitive commands from console history
Sensitive RPC commands such as `walletpassphrase` or `createwallet` may appear in the console history with their arguments redacted. Previously, these entries could still be re-executed if recalled, potentially causing unintended actions. This change prefixes sensitive history entries with a leading character(`!`), marking them as non-executable when called. The console blocks their execution and informs the user that the command was blocked. The help text in `help-console` has been updated to explain this behavior. Test coverage is updated to verify redaction prefixing and ensure commands are properly filtered.
1 parent 5c5704e commit 48fefa8

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

src/qt/rpcconsole.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,13 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
361361
for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
362362
pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
363363
}
364+
365+
bool is_sensitive = !filter_ranges.empty();
366+
367+
// Prefix "!" to mark sensitive commands as non-executable when recalled from history
368+
if (is_sensitive) {
369+
pstrFilteredOut->insert(0, 1, '!');
370+
}
364371
}
365372
switch(state) // final state
366373
{
@@ -405,7 +412,11 @@ void RPCExecutor::request(const QString &command, const QString& wallet_name)
405412
" example: getblock(getblockhash(0) 1)[tx]\n\n"
406413

407414
"Results without keys can be queried with an integer in brackets using the parenthesized syntax.\n"
408-
" example: getblock(getblockhash(0),1)[tx][0]\n\n")));
415+
" example: getblock(getblockhash(0),1)[tx][0]\n\n"
416+
417+
"Commands starting with a leading '!' are blocked from execution.\n"
418+
"These entries are shown for reference only. Remove the '!' or retype to run them.\n"
419+
" example: !walletpassphrase(...)\n\n")));
409420
return;
410421
}
411422
if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, wallet_name)) {
@@ -994,6 +1005,16 @@ void RPCConsole::on_lineEdit_returnPressed()
9941005
return;
9951006
}
9961007

1008+
// Prevent parsing and execution of commands prefixed with '!'
1009+
if (cmd.startsWith('!')) {
1010+
QMessageBox::information(this, tr("Command not executed"), tr(
1011+
"Commands prefixed with '!' are blocked.\n"
1012+
"Remove the '!' or retype to run again."
1013+
1014+
));
1015+
return;
1016+
}
1017+
9971018
std::string strFilteredCmd;
9981019
try {
9991020
std::string dummy;

src/qt/test/rpcnestedtests.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,24 @@ void RPCNestedTests::rpcNestedTests()
8585
QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
8686
QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");
8787

88+
RPCConsole::RPCParseCommandLine(nullptr, result, "createwallet test true", false, &filtered);
89+
QVERIFY(filtered == "!createwallet(…)");
90+
RPCConsole::RPCParseCommandLine(nullptr, result, "createwalletdescriptor abc", false, &filtered);
91+
QVERIFY(filtered == "!createwalletdescriptor(…)");
92+
RPCConsole::RPCParseCommandLine(nullptr, result, "migratewallet abc abc", false, &filtered);
93+
QVERIFY(filtered == "!migratewallet(…)");
8894
RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc", false, &filtered);
89-
QVERIFY(filtered == "signmessagewithprivkey(…)");
95+
QVERIFY(filtered == "!signmessagewithprivkey(…)");
9096
RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc,def", false, &filtered);
91-
QVERIFY(filtered == "signmessagewithprivkey(…)");
97+
QVERIFY(filtered == "!signmessagewithprivkey(…)");
9298
RPCConsole::RPCParseCommandLine(nullptr, result, "signrawtransactionwithkey(abc)", false, &filtered);
93-
QVERIFY(filtered == "signrawtransactionwithkey(…)");
99+
QVERIFY(filtered == "!signrawtransactionwithkey(…)");
94100
RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrase(help())", false, &filtered);
95-
QVERIFY(filtered == "walletpassphrase(…)");
101+
QVERIFY(filtered == "!walletpassphrase(…)");
96102
RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
97-
QVERIFY(filtered == "walletpassphrasechange(…)");
103+
QVERIFY(filtered == "!walletpassphrasechange(…)");
98104
RPCConsole::RPCParseCommandLine(nullptr, result, "help(encryptwallet(abc, def))", false, &filtered);
99-
QVERIFY(filtered == "help(encryptwallet(…))");
105+
QVERIFY(filtered == "!help(encryptwallet(…))");
100106

101107
RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest");
102108
QVERIFY(result == "[]");

0 commit comments

Comments
 (0)