wallet: read RPC crypto fields with memcpy
What changed, and why it matters
This commit changes how the Monero wallet RPC server reads certain fixed-size cryptographic identifiers (payment IDs and transaction IDs) from user-supplied blobs. It replaces direct pointer casting with explicit memory copying. The main practical effect is avoiding undefined behavior when the input buffer is not properly aligned for the target type, which could in theory cause crashes or misbehavior on strict CPU architectures. There is no direct evidence in the commit that this fixes an exploitable security vulnerability.
Treat as a defensive hardening change. Include in normal patch review and regression testing. No urgent security response is warranted based solely on this diff, but consider whether unaligned access on these paths could cause crashes or non-deterministic behavior on affected platforms.
Security signals we found
Eliminates undefined behavior from unaligned pointer dereference on crypto::hash/crypto::hash8
Applies to RPC input parsing paths reachable by wallet RPC clients
No bounds check changes; size checks already exist before the casts
No explicit security framing or CVE in commit message
Evidence from the diff
The patch removes reinterpret_cast
Changed components
src/wallet/wallet_rpc_server.cppwallet RPC input parsing for payment IDs and transaction IDsInspect captured patch +10 / −6
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index e28f9ba..2dae20f 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -34,6 +34,7 @@
#include <boost/preprocessor/stringize.hpp>
#include <cstdint>
#include <chrono>
+#include <cstring>
#include "include_base_utils.h"
using namespace epee;
@@ -2103,11 +2104,11 @@ namespace tools
if(sizeof(payment_id) == payment_id_blob.size())
{
- payment_id = *reinterpret_cast<const crypto::hash*>(payment_id_blob.data());
+ memcpy(&payment_id, payment_id_blob.data(), sizeof(payment_id));
}
else if(sizeof(payment_id8) == payment_id_blob.size())
{
- payment_id8 = *reinterpret_cast<const crypto::hash8*>(payment_id_blob.data());
+ memcpy(&payment_id8, payment_id_blob.data(), sizeof(payment_id8));
memcpy(payment_id.data, payment_id8.data, 8);
memset(payment_id.data + 8, 0, 24);
}
@@ -2561,7 +2562,8 @@ namespace tools
return false;
}
- crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_blob.data());
+ crypto::hash txid;
+ memcpy(&txid, txid_blob.data(), sizeof(txid));
txids.push_back(txid);
}
@@ -2592,7 +2594,8 @@ namespace tools
return false;
}
- crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_blob.data());
+ crypto::hash txid;
+ memcpy(&txid, txid_blob.data(), sizeof(txid));
txids.push_back(txid);
}
@@ -2991,7 +2994,7 @@ namespace tools
if(sizeof(txid) == txid_blob.size())
{
- txid = *reinterpret_cast<const crypto::hash*>(txid_blob.data());
+ memcpy(&txid, txid_blob.data(), sizeof(txid));
}
else
{
@@ -3452,7 +3455,8 @@ namespace tools
return false;
}
- crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_blob.data());
+ crypto::hash txid;
+ memcpy(&txid, txid_blob.data(), sizeof(txid));
txids.insert(txid);
}
Why this scored 38/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.