fix(security): remediate high/medium findings from branch audit

Static audit of the wallet surfaced supply-chain, TLS, and secret-lifecycle
issues. This fixes the six High-priority items plus four high-value Medium
items; all build clean (full-node + tests) and the suite passes.

Supply chain / integrity:
- bootstrap: reject zip-slip / path-traversal archive members before writing
  (isSafeArchivePath); the sibling updaters flatten via baseName(), bootstrap
  keeps sub-paths so it validates instead (F2-1).
- bootstrap: require a SHA-256 checksum — fail closed instead of extracting
  unverified chain data when none is published (F2-2).
- xmrig updater: fail closed when a signature is required but no key is pinned,
  matching the daemon updater (was: silent downgrade to checksum-only) (F1-1).
- xmrig/daemon updaters: cap metadata responses (MAXFILESIZE + 16 MiB hard cap
  in the write callback, which also catches chunked/no-Content-Length) (F1-2).

Network / TLS:
- rpc_client: set SSL_VERIFYPEER/VERIFYHOST explicitly instead of relying on
  libcurl defaults (F4-1).
- rpc_client: bound response accumulation at 256 MiB to prevent OOM from a
  compromised daemon (F4-3).
- lite_connection_service: reject remote http:// lite servers (loopback still
  allowed) to prevent a silent TLS downgrade of lightwalletd traffic (F8-1).

Secret lifecycle / fund safety:
- lite controller: propagate the save() result from encrypt/decryptWallet so a
  failed persist is not reported as success (F7-1).
- xmrig_manager: chmod(0600) the pool config before writing the API token /
  wallet address, closing the world-readable window (F5-2).
- app: clear a copied secret from the OS clipboard on shutdown so it does not
  outlive the process when the 45s auto-clear never fires (F3b-1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 01:16:24 -05:00
co-authored by Claude Fable 5
parent 24e8fb4942
commit 5554016029
9 changed files with 145 additions and 19 deletions
+3
View File
@@ -410,6 +410,9 @@ public:
// plaintext. Call pumpSecretClipboardClear() each frame to action the clear.
void copySecretToClipboard(const std::string& secret);
void pumpSecretClipboardClear();
// Immediately clear the clipboard if it still holds the armed secret (ignores the 45s timer).
// Called on app shutdown so a copied key/seed does not outlive the process in the OS clipboard.
void clearSecretClipboardIfArmed();
bool isTransactionRefreshInProgress() const {
return network_refresh_.jobInProgress(services::NetworkRefreshService::Job::Transactions);
}