From 2ddef8c87d77b207268e9fb78c3e7a68c1f04033 Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Thu, 9 Apr 2026 19:36:22 +0100 Subject: [PATCH] fix: Check network ID in `transactionSignFor` (#64) --- include/xrpl/basics/Expected.h | 32 +++++++++++++++++++--- src/xrpld/rpc/detail/TransactionSign.cpp | 34 ++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/include/xrpl/basics/Expected.h b/include/xrpl/basics/Expected.h index 9afb160d9d..295bbd17a5 100644 --- a/include/xrpl/basics/Expected.h +++ b/include/xrpl/basics/Expected.h @@ -166,17 +166,29 @@ public: } constexpr E const& - error() const + error() const& { return Base::error(); } constexpr E& - error() + error() & { return Base::error(); } + constexpr E&& + error() && + { + return std::move(Base::error()); + } + + constexpr E const&& + error() const&& + { + return std::move(Base::error()); + } + constexpr explicit operator bool() const { @@ -233,17 +245,29 @@ public: } constexpr E const& - error() const + error() const& { return Base::error(); } constexpr E& - error() + error() & { return Base::error(); } + constexpr E&& + error() && + { + return std::move(Base::error()); + } + + constexpr E const&& + error() const&& + { + return std::move(Base::error()); + } + constexpr explicit operator bool() const { diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 17c97e4848..5f7f789c4a 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -391,6 +391,28 @@ checkTxJsonFields( return ret; } +static Expected +checkNetworkID(Json::Value const& tx_json, uint32_t appNetworkId) +{ + if (appNetworkId > 1024) + { + if (!tx_json.isMember(jss::NetworkID)) + { + return Unexpected(RPC::make_error( + rpcINVALID_PARAMS, + RPC::missing_field_message("tx_json.NetworkID"))); + } + if (!tx_json[jss::NetworkID].isIntegral() || + tx_json[jss::NetworkID].asUInt() != appNetworkId) + { + return Unexpected(RPC::make_error( + rpcINVALID_PARAMS, + RPC::invalid_field_message("tx_json.NetworkID"))); + } + } + return Expected(); +} + //------------------------------------------------------------------------------ // A move-only struct that makes it easy to return either a Json::Value or a @@ -1199,8 +1221,16 @@ transactionSignFor( if (!tx_json.isObject()) return RPC::object_field_error(jss::tx_json); - // If the tx_json.SigningPubKey field is missing, - // insert an empty one. + if (auto checkResult = + detail::checkNetworkID(tx_json, app.config().NETWORK_ID); + !checkResult) + { + return std::move(checkResult).error(); + } + + // If the tx_json.SigningPubKey field is missing, insert an empty one, + // in order for the `checkMultiSignFields` to not return an error + // for non-multisign transactions. if (!tx_json.isMember(sfSigningPubKey.getJsonName())) tx_json[sfSigningPubKey.getJsonName()] = ""; }