From 5a643b1a7fb7766aa1af1eefe710c2d08352d0ab Mon Sep 17 00:00:00 2001 From: Shawn Xie <35279399+shawnxie999@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:36:54 -0400 Subject: [PATCH] fix: assorted safety checks (#7030) --- .../tx/transactors/token/ConfidentialMPTClawback.cpp | 7 ++++++- .../transactors/token/ConfidentialMPTConvertBack.cpp | 12 +++++++++--- .../tx/transactors/token/ConfidentialMPTSend.cpp | 4 ++++ src/test/app/ConfidentialTransfer_test.cpp | 8 ++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp index cd5bdf2937..5018a93c3f 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp @@ -95,7 +95,8 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx) // Sanity check: claw amount can not exceed confidential outstanding amount auto const amount = ctx.tx[sfMPTAmount]; - if (amount > (*sleIssuance)[~sfConfidentialOutstandingAmount].value_or(0)) + if (amount > (*sleIssuance)[~sfConfidentialOutstandingAmount].value_or(0) || + amount > (*sleIssuance)[sfOutstandingAmount]) return tecINSUFFICIENT_FUNDS; auto const contextHash = @@ -162,10 +163,14 @@ ConfidentialMPTClawback::doApply() // Decrease Global Confidential Outstanding Amount auto const oldCOA = (*sleIssuance)[sfConfidentialOutstandingAmount]; + if (clawAmount > oldCOA) + return tecINTERNAL; // LCOV_EXCL_LINE (*sleIssuance)[sfConfidentialOutstandingAmount] = oldCOA - clawAmount; // Decrease Global Total Outstanding Amount auto const oldOA = (*sleIssuance)[sfOutstandingAmount]; + if (clawAmount > oldOA) + return tecINTERNAL; // LCOV_EXCL_LINE (*sleIssuance)[sfOutstandingAmount] = oldOA - clawAmount; view().update(sleHolderMPToken); diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp index 66b83a1d8f..c28b70078f 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp @@ -139,7 +139,8 @@ ConfidentialMPTConvertBack::preclaim(PreclaimContext const& ctx) if (!sleIssuance) return tecOBJECT_NOT_FOUND; - if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount)) + if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount) || + !sleIssuance->isFieldPresent(sfIssuerEncryptionKey)) return tecNO_PERMISSION; bool const hasAuditor = ctx.tx.isFieldPresent(sfAuditorEncryptedAmount); @@ -209,9 +210,14 @@ ConfidentialMPTConvertBack::doApply() // Converting back increases regular balance and decreases confidential // outstanding. This is the inverse of Convert. + if (amt > maxMPTokenAmount - amtToConvertBack) + return tecINTERNAL; // LCOV_EXCL_LINE (*sleMptoken)[sfMPTAmount] = amt + amtToConvertBack; - (*sleIssuance)[sfConfidentialOutstandingAmount] = - (*sleIssuance)[sfConfidentialOutstandingAmount] - amtToConvertBack; + + auto const coa = (*sleIssuance)[~sfConfidentialOutstandingAmount].value_or(0); + if (coa < amtToConvertBack) + return tecINTERNAL; // LCOV_EXCL_LINE + (*sleIssuance)[sfConfidentialOutstandingAmount] = coa - amtToConvertBack; std::optional const auditorEc = ctx_.tx[~sfAuditorEncryptedAmount]; diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp index 6fe98c7687..c9b9409452 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp @@ -37,6 +37,10 @@ ConfidentialMPTSend::preflight(PreflightContext const& ctx) if (account == ctx.tx[sfDestination]) return temMALFORMED; + // Issuer cannot be the destination + if (ctx.tx[sfDestination] == issuer) + return temMALFORMED; + // Check the length of the encrypted amounts if (ctx.tx[sfSenderEncryptedAmount].length() != ecGamalEncryptedTotalLength || ctx.tx[sfDestinationEncryptedAmount].length() != ecGamalEncryptedTotalLength || diff --git a/src/test/app/ConfidentialTransfer_test.cpp b/src/test/app/ConfidentialTransfer_test.cpp index 638801c839..fb36b3d6b2 100644 --- a/src/test/app/ConfidentialTransfer_test.cpp +++ b/src/test/app/ConfidentialTransfer_test.cpp @@ -2111,6 +2111,14 @@ class ConfidentialTransfer_test : public beast::unit_test::suite .err = temMALFORMED, }); + // can not send to issuer + mptAlice.send({ + .account = bob, + .dest = alice, + .amt = 10, + .err = temMALFORMED, + }); + // sender encrypted amount wrong length mptAlice.send({ .account = bob,