@@ -195,6 +195,34 @@ func TestCallbackInvokedWhenSetLate(t *testing.T) {
195195 require .True (t , called )
196196}
197197
198+ // TestQuerySequenceCrashesSocketClient reproduces a vulnerability where calling
199+ // QuerySequence over the socket ABCI transport causes the client to stop with
200+ // an error because resMatchesReq is missing the QuerySequence case. When this
201+ // happens in production, killTMOnClientError terminates the entire node.
202+ // A remote peer can trigger this by sending a SeenTx message with a non-empty
203+ // Signer field, which causes the CAT mempool reactor to call QuerySequence
204+ // before validating the message fields.
205+ func TestQuerySequenceCrashesSocketClient (t * testing.T ) {
206+ ctx , cancel := context .WithCancel (context .Background ())
207+ defer cancel ()
208+
209+ app := types.BaseApplication {}
210+ _ , c := setupClientServer (t , app )
211+
212+ // Call QuerySequence over the socket transport. If the bug is present,
213+ // the socket client will stop itself because resMatchesReq returns false
214+ // for Request_QuerySequence <-> Response_QuerySequence.
215+ resp , err := c .QuerySequence (ctx , & types.RequestQuerySequence {
216+ Signer : []byte ("test-signer" ),
217+ })
218+
219+ // With the bug: err != nil and c.Error() != nil (client stopped itself).
220+ // With the fix: err == nil, resp is valid, client remains running.
221+ require .NoError (t , err , "QuerySequence should not cause socket client error" )
222+ require .NotNil (t , resp , "QuerySequence should return a response" )
223+ require .NoError (t , c .Error (), "socket client should still be running without error" )
224+ }
225+
198226type blockedABCIApplication struct {
199227 wg * sync.WaitGroup
200228 types.BaseApplication
0 commit comments