fix(security): delete the plaintext key export after decrypt-wallet import (W2-1)
Removing wallet encryption z_exportwallet'd every private key in cleartext to <datadir>/obsidiandecryptexport<ts>, re-imported it, and never deleted it — leaving a full plaintext dump of every key on disk permanently. The decrypt flow now scrubs (best-effort in-place zero-overwrite) and removes that file as soon as the z_importwallet attempt resolves, on both the success and failure paths. Recovery, if ever needed, remains the encrypted backup (wallet.dat.encrypted.bak), never this file. Second fix in the wallet-hardening P0-A cluster (docs/wallet-hardening.md). Not unit-testable (fs I/O in a deep worker lambda); build-clean, ctest 1/1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
#include <ctime>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
@@ -1606,6 +1608,27 @@ void App::renderDecryptWalletDialog() {
|
||||
WalletSecurityImportRpcAdapter importAdapter(rpc_.get(), saved_config_);
|
||||
auto importResult = services::WalletSecurityWorkflowExecutor::importWallet(
|
||||
importAdapter, exportPath);
|
||||
|
||||
// The plaintext key export (obsidiandecryptexport…) has served its purpose now
|
||||
// that the import attempt has resolved — scrub and remove it so a full cleartext
|
||||
// dump of every private key isn't left on disk forever. Recovery, if ever needed,
|
||||
// is the encrypted backup (wallet.dat.encrypted.bak), never this file.
|
||||
{
|
||||
std::error_code delEc;
|
||||
const auto sz = std::filesystem::file_size(exportPath, delEc);
|
||||
if (!delEc && sz > 0) {
|
||||
std::fstream scrub(exportPath,
|
||||
std::ios::binary | std::ios::in | std::ios::out);
|
||||
if (scrub) {
|
||||
const std::vector<char> zeros(static_cast<size_t>(sz), 0);
|
||||
scrub.write(zeros.data(), static_cast<std::streamsize>(sz));
|
||||
scrub.flush();
|
||||
}
|
||||
}
|
||||
std::filesystem::remove(exportPath, delEc);
|
||||
DEBUG_LOGF("[decrypt] removed plaintext key export after import\n");
|
||||
}
|
||||
|
||||
if (!importResult.ok) {
|
||||
std::string err = importResult.error;
|
||||
if (worker_) {
|
||||
|
||||
Reference in New Issue
Block a user