wallet2: validate legacy transfer output indices
What changed, and why it matters
This commit adds a safety check when loading older Monero wallet data. It ensures that a stored 'output index' (which points to a specific coin within a past transaction) does not point past the number of outputs that transaction actually has. Without this check, a malformed or manipulated old wallet file could reference a non-existent output, potentially causing crashes or undefined behavior when the wallet later uses that index.
Treat as a security-hardening fix for legacy wallet deserialization. Include in release notes and backport to maintained branches. Users with old wallet caches should ensure they are on a patched version before loading untrusted wallet files. No immediate network-wide action is indicated.
Security signals we found
Out-of-bounds index validation added during deserialization
Legacy data format specifically targeted (ver < 4)
Throws archive exception to abort loading invalid state
Reported by external parties (xmrack and MAGIC Monero Fund)
Evidence from the diff
In wallet2_boost_serialization.h, the initialize_transfer_details deserialization hook now throws boost::archive::archive_exception if the archive version is below 4 and x.m_internal_output_index >= x.m_tx.vout.size(). This validates legacy transfer_details records during wallet load, preventing out-of-bounds output indices from being accepted into memory. The fix is narrow and only applies to pre-version-4 serialized data.
Changed components
src/wallet/wallet2_basic/wallet2_boost_serialization.hwallet2_basic::transfer_details deserializationlegacy wallet cache / archive loading pathsInspect captured patch +3 / −0
diff --git a/src/wallet/wallet2_basic/wallet2_boost_serialization.h b/src/wallet/wallet2_basic/wallet2_boost_serialization.h
index e693c4a..9973a02 100644
--- a/src/wallet/wallet2_basic/wallet2_boost_serialization.h
+++ b/src/wallet/wallet2_basic/wallet2_boost_serialization.h
@@ -35,6 +35,7 @@
#include "wallet2_types.h"
//third party headers
+#include <boost/archive/archive_exception.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/vector.hpp>
@@ -71,6 +72,8 @@ template <class Archive>
std::enable_if_t<Archive::is_loading::value>
initialize_transfer_details(Archive &a, wallet2_basic::transfer_details &x, const unsigned int ver)
{
+ if (ver < 4 && x.m_internal_output_index >= x.m_tx.vout.size())
+ throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Invalid transfer output index");
if (ver < 1)
{
x.m_mask = rct::identity();
Why this scored 57/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.