Skip to content

P2: Security Hardening - Input Validation and Resource Limits #50

@U0001F3A2

Description

@U0001F3A2

Overview

This issue tracks several related security and resilience improvements identified during a comprehensive codebase review. These issues share a common theme: insufficient input validation and resource limits that could lead to DOS attacks or resource exhaustion in production.

Issues

1. Missing Proof Size Validation (DOS Vector)

Severity: MEDIUM
Location: internal/orchestrator/statefetcher.go:386-394

Problem: Proof validation checks node count (max 128) but doesn't validate individual node sizes:

if len(accountProof) > maxProofNodes {
    return fmt.Errorf("account proof too large: %d nodes (max %d)", ...)
}

Risk: Attacker could send 128 proof nodes, each kilobytes large, causing memory exhaustion.

Fix: Add per-node size limit (max 1KB per node for Ethereum tries):

const maxProofNodeSize = 1024 // bytes

for i, node := range accountProof {
    if len(node) > maxProofNodeSize {
        return fmt.Errorf("proof node %d too large: %d bytes (max %d)", i, len(node), maxProofNodeSize)
    }
}

2. No Block Size Limits

Severity: MEDIUM
Location: internal/shard/chain.go:290-380

Problem: ProduceBlock() doesn't limit transaction count or cumulative block size.

Risk: Pathological transactions could produce gigantic blocks that:

  • Exhaust memory during serialization
  • Cause network congestion during broadcast
  • Slow down block processing on receivers

Fix: Add constants and enforcement:

const (
    MaxTransactionsPerBlock = 1000
    MaxBlockSize = 10 * 1024 * 1024 // 10MB
)

func (c *Chain) ProduceBlock(evmState *EVMState) (*protocol.StateShardBlock, error) {
    // Early exit if too many transactions
    if len(c.currentTxs) > MaxTransactionsPerBlock {
        c.currentTxs = c.currentTxs[:MaxTransactionsPerBlock]
        log.Printf("Block capped at %d transactions", MaxTransactionsPerBlock)
    }
    // ... rest of function
}

3. Insufficient Validation of HTTP Responses

Severity: MEDIUM
Location: internal/orchestrator/statefetcher.go:163-169

Problem: After deserializing fetch response, no validation of:

  • Balance (could be negative or impossibly large)
  • Code size (could exceed block gas limit)
  • CodeHash correctness (should match keccak256 of Code)

Current Code:

var fetchResp FetchStateResponse
if err := json.Unmarshal(body, &fetchResp); err != nil {
    return nil, fmt.Errorf("unmarshal fetch response: %w", err)
}
if !fetchResp.Success {
    return &fetchResp, fmt.Errorf("fetch failed: %s", fetchResp.Error)
}
// No validation of Balance, Code, CodeHash

Fix: Add validation after unmarshal:

if fetchResp.Balance.Sign() < 0 {
    return nil, fmt.Errorf("invalid negative balance")
}
if len(fetchResp.Code) > 24576 { // EIP-170 max contract size
    return nil, fmt.Errorf("code size %d exceeds limit", len(fetchResp.Code))
}
if len(fetchResp.Code) > 0 {
    expectedHash := crypto.Keccak256Hash(fetchResp.Code)
    if fetchResp.CodeHash != expectedHash {
        return nil, fmt.Errorf("code hash mismatch")
    }
}

4. No Authentication on RPC Endpoints

Severity: MEDIUM (for production deployment)
Location: All HTTP handlers

Problem: All HTTP endpoints accept requests from any origin without authentication:

  • /tx/submit - can submit transactions
  • /evm/deploy - can deploy contracts
  • /faucet - can mint tokens
  • /state/fetch - can read state

Current Protection: Relies on Docker network isolation only.

Production Requirements:

  • API key verification for write operations
  • Rate limiting per IP/key
  • Request signing for cross-shard communication

Suggested Approach:

func (s *Server) authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        apiKey := r.Header.Get("X-API-Key")
        if !isValidAPIKey(apiKey) {
            http.Error(w, "unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Implementation Plan

# Task Complexity Priority
1 Add proof node size validation Low (30 min) High
2 Add block size limits Low (1 hour) High
3 Add HTTP response validation Medium (2 hours) Medium
4 Add authentication middleware Medium (4 hours) Low (production)

Acceptance Criteria

  • Proof validation rejects nodes > 1KB
  • Blocks capped at 1000 txs / 10MB
  • State fetch validates balance, code size, code hash
  • Tests added for each validation
  • (Optional) Authentication middleware for production

Related

Labels

P2, security, enhancement

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2High priority - should fix soon

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions