Skip to content

Commit 318eacf

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 redacted 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 redacted. 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 318eacf

File tree

2 files changed

+31
-7
lines changed

2 files changed

+31
-7
lines changed

src/qt/rpcconsole.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,10 @@ 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+
// Prefix "!" to mark redacted commands as non-executable when recalled from history
365+
if (!filter_ranges.empty() && !pstrFilteredOut->starts_with('!')) {
366+
pstrFilteredOut->insert(0, 1, '!');
367+
}
364368
}
365369
switch(state) // final state
366370
{
@@ -405,7 +409,11 @@ void RPCExecutor::request(const QString &command, const QString& wallet_name)
405409
" example: getblock(getblockhash(0) 1)[tx]\n\n"
406410

407411
"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")));
412+
" example: getblock(getblockhash(0),1)[tx][0]\n\n"
413+
414+
"Commands starting with a leading '!' indicate redacted entries.\n"
415+
"Their sensitive arguments were removed and they cannot be executed.\n"
416+
" example: !walletpassphrase(...)\n\n")));
409417
return;
410418
}
411419
if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, wallet_name)) {
@@ -994,6 +1002,16 @@ void RPCConsole::on_lineEdit_returnPressed()
9941002
return;
9951003
}
9961004

1005+
// Prevent execution of redacted entries (prefixed with '!') and notify the user
1006+
if (cmd.startsWith('!')) {
1007+
QMessageBox::information(this, tr("Sensitive command"), tr(
1008+
"Command not executed: this is a redacted entry.\n"
1009+
"Sensitive arguments were removed. Retype the full command to run it again."
1010+
));
1011+
ui->lineEdit->clear();
1012+
return;
1013+
}
1014+
9971015
std::string strFilteredCmd;
9981016
try {
9991017
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)