wallet: fix RPC describe transfer source entry
What changed, and why it matters
This commit fixes a bug in the Monero wallet's RPC 'describe transfer' feature. Previously, the code used the wrong index (real_output_in_tx_index) to look up the real ring member in the list of possible transaction sources. The fix uses the correct index (real_output). This could have caused the RPC response to report the wrong global index and public key for the real source of funds, potentially misleading wallet users or downstream tools that rely on this data.
Review whether the incorrect index could leak or misreport sensitive ring-member information, and confirm the fix is backported to maintained branches. Audit other uses of real_output_in_tx_index versus real_output in the wallet RPC code.
Security signals we found
Incorrect index used to identify real transaction source in RPC output
Potential information disclosure or misattribution of transfer source
Fix aligns source lookup with intended field semantics
Evidence from the diff
In wallet_rpc_server.cpp, the describe_transfer RPC handler builds a list of source entries for a transfer description. Before the patch, it accessed src_in.outputs.at(src_in.real_output_in_tx_index) to obtain the real ring member’s global index and public key. The correct field for indexing into src_in.outputs is src_in.real_output. The patch stores the correct output_entry in a local variable and uses it for both fields. The bug is an index mismatch that could produce incorrect source metadata in RPC responses.
Changed components
src/wallet/wallet_rpc_server.cppwallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFERInspect captured patch +3 / −2
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index f19e645..7f9affa 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1564,11 +1564,12 @@ namespace tools
for (size_t s = 0; s < cd.sources.size(); ++s)
{
const cryptonote::tx_source_entry &src_in = cd.sources[s];
+ const cryptonote::tx_source_entry::output_entry &real_ring_member = src_in.outputs.at(src_in.real_output);
wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::source &src_out = desc.sources.emplace_back();
src_out.amount = src_in.amount;
- src_out.global_index = src_in.outputs.at(src_in.real_output_in_tx_index).first;
+ src_out.global_index = real_ring_member.first;
src_out.rct = src_in.rct;
- src_out.pubkey = epee::string_tools::pod_to_hex(src_in.outputs.at(src_in.real_output_in_tx_index).second);
+ src_out.pubkey = epee::string_tools::pod_to_hex(real_ring_member.second);
desc.amount_in += src_in.amount;
size_t ring_size = src_in.outputs.size();
if (ring_size < desc.ring_size)
Why this scored 26/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.