diff --git a/x/ibc-hooks/move-hooks/message.go b/x/ibc-hooks/move-hooks/message.go index 10c935f3..21aedfb7 100644 --- a/x/ibc-hooks/move-hooks/message.go +++ b/x/ibc-hooks/move-hooks/message.go @@ -78,21 +78,26 @@ func (a *AsyncCallback) UnmarshalJSON(bz []byte) error { return fmt.Errorf("module_name cannot be empty") } - // Validate module address format (assuming it should start with "0x") + // Validate module address format if !strings.HasPrefix(ic.ModuleAddress, "0x") { return fmt.Errorf("invalid module_address format: must start with '0x'") } - // Handle ID based on type + // Handle ID based on type with overflow checking switch v := ic.Id.(type) { case float64: + if v < 0 || v > float64(^uint64(0)) || v != float64(uint64(v)) { + return fmt.Errorf("id value out of range or contains decimals") + } a.Id = uint64(v) case string: - var err error var parsed float64 - if err = json.Unmarshal([]byte(v), &parsed); err != nil { + if err := json.Unmarshal([]byte(v), &parsed); err != nil { return fmt.Errorf("invalid id format: %w", err) } + if parsed < 0 || parsed > float64(^uint64(0)) || parsed != float64(uint64(parsed)) { + return fmt.Errorf("id value out of range or contains decimals") + } a.Id = uint64(parsed) default: return fmt.Errorf("invalid id type: expected string or number") diff --git a/x/ibc-hooks/move-hooks/message_test.go b/x/ibc-hooks/move-hooks/message_test.go index ca2446b5..d6dc03fa 100644 --- a/x/ibc-hooks/move-hooks/message_test.go +++ b/x/ibc-hooks/move-hooks/message_test.go @@ -100,4 +100,70 @@ func Test_Unmarshal_AsyncCallback(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "invalid character") }) + + t.Run("id with decimal value", func(t *testing.T) { + var callback movehooks.AsyncCallback + err := json.Unmarshal([]byte(`{ + "id": 99.5, + "module_address": "0x1", + "module_name": "Counter" + }`), &callback) + require.Error(t, err) + require.Contains(t, err.Error(), "id value out of range or contains decimals") + }) + + t.Run("id with string decimal value", func(t *testing.T) { + var callback movehooks.AsyncCallback + err := json.Unmarshal([]byte(`{ + "id": "99.5", + "module_address": "0x1", + "module_name": "Counter" + }`), &callback) + require.Error(t, err) + require.Contains(t, err.Error(), "id value out of range or contains decimals") + }) + + t.Run("negative id value", func(t *testing.T) { + var callback movehooks.AsyncCallback + err := json.Unmarshal([]byte(`{ + "id": -1, + "module_address": "0x1", + "module_name": "Counter" + }`), &callback) + require.Error(t, err) + require.Contains(t, err.Error(), "id value out of range or contains decimals") + }) + + t.Run("negative string id value", func(t *testing.T) { + var callback movehooks.AsyncCallback + err := json.Unmarshal([]byte(`{ + "id": "-1", + "module_address": "0x1", + "module_name": "Counter" + }`), &callback) + require.Error(t, err) + require.Contains(t, err.Error(), "id value out of range or contains decimals") + }) + + t.Run("id value exceeding uint64 max", func(t *testing.T) { + var callback movehooks.AsyncCallback + err := json.Unmarshal([]byte(`{ + "id": 18446744073709551616, + "module_address": "0x1", + "module_name": "Counter" + }`), &callback) + require.Error(t, err) + require.Contains(t, err.Error(), "id value out of range or contains decimals") + }) + + t.Run("string id value exceeding uint64 max", func(t *testing.T) { + var callback movehooks.AsyncCallback + err := json.Unmarshal([]byte(`{ + "id": "18446744073709551616", + "module_address": "0x1", + "module_name": "Counter" + }`), &callback) + require.Error(t, err) + require.Contains(t, err.Error(), "id value out of range or contains decimals") + }) }