From 15662eb1b1ea9725bdbb6ca0df53fa6dd202c0ea Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Mon, 27 Apr 2026 21:03:00 +0700 Subject: [PATCH] fix(consensus): cap export proposal signatures Limit outbound TMProposeSet export signature attachments to ExportLimits::maxPendingExports so honest proposals stay within the same bound enforced by inbound proposal validation. Extra exports remain unsigned for that proposal and rely on the existing retry/expiry path. --- src/xrpld/app/consensus/ConsensusExtensions.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/xrpld/app/consensus/ConsensusExtensions.cpp b/src/xrpld/app/consensus/ConsensusExtensions.cpp index 42b48a085..aff82ad2a 100644 --- a/src/xrpld/app/consensus/ConsensusExtensions.cpp +++ b/src/xrpld/app/consensus/ConsensusExtensions.cpp @@ -2068,12 +2068,21 @@ ConsensusExtensions::attachExportSignatures( return; auto const signerAcctID = calcAccountID(valPK); + std::uint8_t attached = 0; for (auto const& [stx, meta] : openLedger->txs) { if (!stx || stx->getTxnType() != ttEXPORT) continue; + if (attached >= ExportLimits::maxPendingExports) + { + JLOG(j_.debug()) + << "Export: proposal signature attachment cap reached (max " + << +ExportLimits::maxPendingExports << ")"; + break; + } + auto const txHash = stx->getTransactionID(); // Only attach our sig on the first proposal this round. @@ -2113,6 +2122,7 @@ ConsensusExtensions::attachExportSignatures( if (sigBuf.size() > 0) s.addRaw(Slice(sigBuf.data(), sigBuf.size())); prop.add_exportsignatures(s.peekData().data(), s.peekData().size()); + ++attached; //@@end export-attach-wire-sigs // Only store if we actually produced a signature.