security: scrub on-screen secrets on lock; redact lite console secret args; no-shell wallet rebuild
- Locking the wallet (manual / auto / lite) now calls wipeDisplayedSecrets(), which scrubs + closes any revealed seed phrase, migration seed, or exported key — previously a locked wallet could leave the phrase/key on screen and resident. Runs synchronously, before the async lock round-trip. - The console secret-arg redaction list only had full-node RPC names, so lite verbs (import / timport / encrypt / decrypt / unlock) echoed keys and passphrases into the scrollback and up-arrow history; added them. - The offline wallet-rebuild helper was invoked via a shell string (popen "sh -c") built from paths including the wallet filename, so a crafted name could inject a command; it now refuses any path with a shell metacharacter (rc stays -1 and the existing verify-before-swap fails safe). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+15
-2
@@ -5399,6 +5399,7 @@ bool App::lockLiteWallet()
|
||||
if (!lite_wallet_) return false;
|
||||
const bool ok = lite_wallet_->lockWallet();
|
||||
if (ok) {
|
||||
wipeDisplayedSecrets(); // scrub any revealed seed/key display on lock (matches full-node)
|
||||
// Full-node App::lockWallet() sets state_.locked synchronously; the lite backend `lock`
|
||||
// doesn't, and state_.locked only refreshes on the next ~2s poll. Mirror the full-node
|
||||
// behavior here and tear down the chat session NOW so no decrypted store / unlocked DB key
|
||||
@@ -6917,9 +6918,21 @@ void App::rebuildWalletDatabase()
|
||||
// 3. Run the helper (src -> tmpOut). Quote both paths; capture its JSON line. Windowless
|
||||
// (runHiddenCapture) so a wallet rebuild never flashes a cmd.exe console; it runs the
|
||||
// helper via CreateProcess directly on Windows, so no cmd.exe outer-quote wrap is needed.
|
||||
const std::string cmd = "\"" + helper + "\" \"" + src + "\" \"" + tmpOut + "\"";
|
||||
// runHiddenCapture runs this via popen("sh -c …") on POSIX, where $( ), backticks and an
|
||||
// embedded \" still expand inside the double-quotes — so a crafted wallet filename (src is
|
||||
// datadir + the activeWalletName setting) could inject a shell command. Refuse any path
|
||||
// carrying a shell metacharacter; rc stays -1 and the verify-before-swap below fails safe.
|
||||
auto shellSafe = [](const std::string& p) {
|
||||
return p.find_first_of("\"'`$;&|<>^\n\r") == std::string::npos;
|
||||
};
|
||||
int rc = -1;
|
||||
const std::string jout = util::Platform::runHiddenCapture(cmd, /*mergeStderr=*/false, &rc);
|
||||
std::string jout;
|
||||
if (shellSafe(helper) && shellSafe(src) && shellSafe(tmpOut)) {
|
||||
const std::string cmd = "\"" + helper + "\" \"" + src + "\" \"" + tmpOut + "\"";
|
||||
jout = util::Platform::runHiddenCapture(cmd, /*mergeStderr=*/false, &rc);
|
||||
} else {
|
||||
DEBUG_LOGF("[App] wallet-rebuild refused: shell metacharacter in a path\n");
|
||||
}
|
||||
DEBUG_LOGF("[App] wallet-rebuild helper rc=%d out=%s\n", rc, jout.c_str());
|
||||
|
||||
// 4. Verify-before-swap: the output must be a readable BDB with the fund-critical keys.
|
||||
|
||||
Reference in New Issue
Block a user