wallet: Throw if unknown entry is found in mapValue
What changed, and why it matters
This Bitcoin Core wallet patch makes the wallet stricter when reading old transaction metadata. Previously, unknown entries in a wallet's internal 'mapValue' data store were silently ignored. Now the wallet will refuse to load if it sees an entry it does not recognize, and it also removes two obsolete fields ('fromaccount' and 'spent') before checking. The goal is to prevent accidental loss of user data when older wallet formats are loaded in newer software, not to fix an active remote attack.
Treat as a wallet robustness improvement rather than an urgent vulnerability. Users with old wallets should back up wallet.dat before upgrading to a release containing this change, because wallets containing unexpected mapValue entries will now fail to load instead of loading with data dropped. Developers should verify that no supported wallet version legitimately emits other mapValue keys.
Security signals we found
Data-integrity hardening: unknown wallet metadata now causes load failure instead of silent discard
Legacy field cleanup: 'fromaccount' and 'spent' erased before validation
Defense-in-depth against future mapValue removal causing data loss
Evidence from the diff
In src/wallet/transaction.h, CWalletTx::UnserializeFromDisk now erases legacy mapValue keys ‘fromaccount’ and ‘spent’ before iterating the remaining entries, and throws std::runtime_error if any key is not in the expected whitelist (n, timesmart, comment, to, replaces_txid, replaced_by_txid). Previously those legacy keys were erased after the loop, so they were effectively ignored. The change converts silent data dropping into a hard failure at wallet load time to surface unexpected state.
Changed components
src/wallet/transaction.hCWalletTx::UnserializeFromDiskBitcoin Core wallet loading/deserializationInspect captured patch +5 / −2
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index 1fb14c40..23f99042 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -330,6 +330,8 @@ public:
m_state = TxStateInterpretSerialized({serialized_block_hash, serializedIndex});
+ mapValue.erase("fromaccount");
+ mapValue.erase("spent");
for (const auto& [key, value] : mapValue) {
if (key == "n") nOrderPos = LocaleIndependentAtoi<int64_t>(value);
else if (key == "timesmart") nTimeSmart = LocaleIndependentAtoi<int64_t>(value);
@@ -339,10 +341,11 @@ public:
else if (key == "to") m_comment_to = value;
else if (key == "replaces_txid") m_replaces_txid = Txid::FromHex(value);
else if (key == "replaced_by_txid") m_replaced_by_txid = Txid::FromHex(value);
+ else {
+ throw std::runtime_error("Unexpected value in CWalletTx strings value map");
+ }
}
- mapValue.erase("fromaccount");
- mapValue.erase("spent");
mapValue.erase("n");
mapValue.erase("timesmart");
mapValue.erase("from");
Why this scored 31/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.