diff --git a/src/evo/netinfo.cpp b/src/evo/netinfo.cpp index a3f53693ccaf..48eae4e11232 100644 --- a/src/evo/netinfo.cpp +++ b/src/evo/netinfo.cpp @@ -601,6 +601,11 @@ NetInfoStatus ExtNetInfo::Validate() const // Purpose if present in map must have at least one entry return NetInfoStatus::Malformed; } + if (entries.size() > MAX_ENTRIES_EXTNETINFO) { + // Per-purpose entry count is bounded at insertion; a deserialized object + // may exceed it and must be rejected here + return NetInfoStatus::MaxLimit; + } if (HasAddrDuplicates(entries)) { return NetInfoStatus::Duplicate; } diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index bc68f76664f1..72ba23ca3206 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -883,11 +883,13 @@ static bool CheckService(const ProTx& proTx, TxValidationState& state) return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-bad"); case NetInfoStatus::Success: return true; - // Shouldn't be possible during self-checks + // Reachable through a serialized netInfo that bypasses the in-memory builder's checks case NetInfoStatus::BadInput: + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-entry"); case NetInfoStatus::Duplicate: + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry"); case NetInfoStatus::MaxLimit: - assert(false); + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-maxlimit"); } // no default case, so the compiler can warn about missing cases assert(false); } diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index 3af64daa6347..116686892aa4 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -14,12 +15,14 @@ #include #include #include +#include #include #include #include