feat(rpc): scrub the raw response body for secret-bearing calls (B7)
The secret exports (z_exportmnemonic / z_exportkey / dumpprivkey) already scrub the parsed value at the call site, but the raw HTTP response string those RPCs build — the curl write buffer, which holds the same secret in the clear — was freed without zeroing. That's the "fuller fix belongs in the RPC layer" the identity-fetch comment flagged. Add RPCClient::callSecret(), a call() variant that sodium_memzeros the raw response body after parsing (on success and on throw). NRVO makes the returned string the very buffer curl wrote into, so one wipe covers it. Route every secret-bearing export through it: chat identity (mnemonic + z_exportkey fallback), Settings seed-phrase + single-key export, Export-all-keys, and the migrate-to-seed isolated-node mnemonic export. Purely additive — the parsed result is byte-identical, so no behavior change (safe for the fund-critical migrate path). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -370,6 +370,27 @@ json RPCClient::call(const std::string& method, const json& params)
|
||||
return parseRpcResult(http_code, response_data);
|
||||
}
|
||||
|
||||
json RPCClient::callSecret(const std::string& method, const json& params)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(curl_mutex_);
|
||||
if (!impl_->curl) {
|
||||
throw std::runtime_error("Not connected");
|
||||
}
|
||||
|
||||
// Zero the raw response body whether parsing succeeds or throws — it holds the secret in the
|
||||
// clear (the curl write buffer performCall returns), and would otherwise be freed un-wiped (B7).
|
||||
long http_code = 0;
|
||||
std::string response_data = performCall(method, params, http_code);
|
||||
try {
|
||||
json result = parseRpcResult(http_code, response_data);
|
||||
if (!response_data.empty()) sodium_memzero(&response_data[0], response_data.size());
|
||||
return result;
|
||||
} catch (...) {
|
||||
if (!response_data.empty()) sodium_memzero(&response_data[0], response_data.size());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
json RPCClient::call(const std::string& method, const json& params, long timeoutSec)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(curl_mutex_);
|
||||
|
||||
Reference in New Issue
Block a user