Files
mev-beta/docs/planning/08_MEDIUM-003_Sensitive_Logging_Plan.md
Krypto Kajun 850223a953 fix(multicall): resolve critical multicall parsing corruption issues
- Added comprehensive bounds checking to prevent buffer overruns in multicall parsing
- Implemented graduated validation system (Strict/Moderate/Permissive) to reduce false positives
- Added LRU caching system for address validation with 10-minute TTL
- Enhanced ABI decoder with missing Universal Router and Arbitrum-specific DEX signatures
- Fixed duplicate function declarations and import conflicts across multiple files
- Added error recovery mechanisms with multiple fallback strategies
- Updated tests to handle new validation behavior for suspicious addresses
- Fixed parser test expectations for improved validation system
- Applied gofmt formatting fixes to ensure code style compliance
- Fixed mutex copying issues in monitoring package by introducing MetricsSnapshot
- Resolved critical security vulnerabilities in heuristic address extraction
- Progress: Updated TODO audit from 10% to 35% complete

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 00:12:55 -05:00

13 KiB

MEDIUM-003: Sensitive Information Logging - Detailed Fix Plan

Issue ID: MEDIUM-003
Category: Security
Priority: Medium
Status: Not Started
Generated: October 9, 2025
Estimate: 2-3 hours

Overview

This plan implements secure logging practices to prevent sensitive information such as addresses, transaction data, and private keys from being logged inappropriately. The implementation will include log sanitization, configurable filtering, secure audit logging, and log encryption.

Current Implementation Issues

  • Sensitive information may be logged in plain text
  • No configurable filtering for sensitive data in logs
  • Lack of secure audit logging format
  • No encryption for sensitive audit trails

Implementation Tasks

1. Implement Log Sanitization for Addresses and Transaction Data

Task ID: MEDIUM-003.1
Time Estimate: 1 hour
Dependencies: None

Create comprehensive log sanitization functions:

  • Identify and mask sensitive data patterns (addresses, keys, transaction data)
  • Implement configurable sanitization rules
  • Create safe logging wrapper functions
  • Ensure sanitization works with structured logging
import (
    "regexp"
    "strings"
)

type LogSanitizer struct {
    patterns map[string]*regexp.Regexp
}

func NewLogSanitizer() *LogSanitizer {
    // Precompile regex patterns for performance
    patterns := map[string]*regexp.Regexp{
        "ethereum_address": regexp.MustCompile(`(?i)0x[a-f0-9]{40}`),
        "private_key":      regexp.MustCompile(`(?i)0x[a-f0-9]{64}`),
        "transaction_hash": regexp.MustCompile(`(?i)0x[a-f0-9]{64}`),
        "wallet_seed":      regexp.MustCompile(`(?i)\b([a-z]{3,}\s){11,23}[a-z]{3,}\b`), // Basic seed phrase pattern
    }
    
    return &LogSanitizer{
        patterns: patterns,
    }
}

func (ls *LogSanitizer) Sanitize(message string) string {
    sanitized := message
    
    for _, pattern := range ls.patterns {
        sanitized = pattern.ReplaceAllStringFunc(sanitized, func(match string) string {
            // Mask the middle portion of the sensitive data
            if len(match) > 8 {
                return match[:6] + "..." + match[len(match)-4:]
            }
            return "***"
        })
    }
    
    return sanitized
}

func (ls *LogSanitizer) SanitizeStruct(data interface{}) interface{} {
    // For structured logging, sanitize string fields recursively
    switch v := data.(type) {
    case string:
        return ls.Sanitize(v)
    case map[string]interface{}:
        result := make(map[string]interface{})
        for key, value := range v {
            result[key] = ls.SanitizeStruct(value)
        }
        return result
    case []interface{}:
        result := make([]interface{}, len(v))
        for i, value := range v {
            result[i] = ls.SanitizeStruct(value)
        }
        return result
    default:
        return data
    }
}

2. Add Configurable Log Level Filtering for Sensitive Information

Task ID: MEDIUM-003.2
Time Estimate: 0.5 hours
Dependencies: MEDIUM-003.1

Implement configurable log filtering for sensitive data:

  • Allow configuration of what sensitive data is logged at different levels
  • Implement log level-specific sanitization
  • Create configuration options for sensitive data handling
  • Provide ability to disable logging of specific sensitive fields
type LogConfig struct {
    SanitizeAddresses      bool
    SanitizePrivateKeys    bool
    SanitizeTransactionIDs bool
    LogLevel               string
    SanitizeLevel          string  // Level at which sanitization is required
}

func (lc *LogConfig) ShouldSanitize() bool {
    // Define log levels: debug, info, warn, error
    sanitizeLevelOrder := map[string]int{
        "debug": 0,
        "info":  1,
        "warn":  2,
        "error": 3,
    }
    
    currentLevel, ok := sanitizeLevelOrder[lc.LogLevel]
    if !ok {
        currentLevel = 1  // Default to info level
    }
    
    requiredLevel, ok := sanitizeLevelOrder[lc.SanitizeLevel]
    if !ok {
        requiredLevel = 1  // Default to info level
    }
    
    return currentLevel >= requiredLevel
}

func (lc *LogConfig) ApplyFilters(data interface{}) interface{} {
    if !lc.ShouldSanitize() {
        return data
    }
    
    // Apply field-specific filtering based on config
    switch v := data.(type) {
    case map[string]interface{}:
        result := make(map[string]interface{})
        for key, value := range v {
            // Filter out or mask sensitive fields based on config
            if lc.isSensitiveField(key) {
                result[key] = lc.maskSensitiveValue(key, value)
            } else {
                result[key] = value
            }
        }
        return result
    default:
        return data
    }
}

func (lc *LogConfig) isSensitiveField(key string) bool {
    sensitiveFields := map[string]bool{
        "private_key":     lc.SanitizePrivateKeys,
        "privateKey":      lc.SanitizePrivateKeys,
        "address":         lc.SanitizeAddresses,
        "recipient":       lc.SanitizeAddresses,
        "sender":          lc.SanitizeAddresses,
        "transaction_id":  lc.SanitizeTransactionIDs,
        "transactionId":   lc.SanitizeTransactionIDs,
        "hash":            lc.SanitizeTransactionIDs,
    }
    
    return sensitiveFields[key]
}

func (lc *LogConfig) maskSensitiveValue(field string, value interface{}) interface{} {
    if str, ok := value.(string); ok {
        if len(str) > 8 {
            return str[:6] + "..." + str[len(str)-4:]
        }
        return "***"
    }
    return "***"  // For non-string sensitive values
}

3. Create Secure Audit Logging Format

Task ID: MEDIUM-003.3
Time Estimate: 0.5 hours
Dependencies: MEDIUM-003.1, MEDIUM-003.2

Design and implement secure audit logging format:

  • Standardized format for audit logs
  • Consistent field naming and structure
  • Proper sanitization of audit data
  • Separation of regular logs from audit logs
type SecureAuditLogger struct {
    logger     *Logger
    sanitizer  *LogSanitizer
    config     *LogConfig
    auditFile  string
}

type AuditEvent struct {
    Timestamp    time.Time         `json:"timestamp"`
    EventType    string           `json:"event_type"`
    Actor        string           `json:"actor"`
    Action       string           `json:"action"`
    Resource     string           `json:"resource"`
    Outcome      string           `json:"outcome"`
    SourceIP     string           `json:"source_ip,omitempty"`
    Details      map[string]interface{} `json:"details"`
}

func (sal *SecureAuditLogger) LogAuditEvent(eventType, actor, action, resource, outcome string, details map[string]interface{}) error {
    auditEvent := AuditEvent{
        Timestamp: time.Now(),
        EventType: eventType,
        Actor:     actor,
        Action:    action,
        Resource:  resource,
        Outcome:   outcome,
        Details:   sal.config.ApplyFilters(sal.sanitizer.SanitizeStruct(details)).(map[string]interface{}),
    }
    
    // Serialize and write to secure audit log
    data, err := json.Marshal(auditEvent)
    if err != nil {
        return fmt.Errorf("failed to serialize audit event: %w", err)
    }
    
    // Write to secured audit log file
    return sal.writeSecureLog(data)
}

func (sal *SecureAuditLogger) writeSecureLog(data []byte) error {
    // Ensure the audit log file has secure permissions
    // This is a simplified example - implement proper secure file handling
    file, err := os.OpenFile(sal.auditFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
    if err != nil {
        return fmt.Errorf("failed to open audit log file: %w", err)
    }
    defer file.Close()
    
    _, err = file.Write(append(data, '\n'))
    return err
}

4. Implement Log Encryption for Sensitive Audit Trails

Task ID: MEDIUM-003.4
Time Estimate: 1 hour
Dependencies: MEDIUM-003.1, MEDIUM-003.2, MEDIUM-003.3

Implement encryption for sensitive audit trails:

  • Use authenticated encryption for audit logs
  • Implement key management for log encryption
  • Ensure encrypted logs can be properly searched and analyzed
  • Provide secure backup and recovery for log encryption keys
import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "io"
)

type EncryptedAuditLogger struct {
    auditLogger *SecureAuditLogger
    block       cipher.Block
    gcm         cipher.AEAD
}

func NewEncryptedAuditLogger(encryptionKey []byte, auditFile string) (*EncryptedAuditLogger, error) {
    // Create a new AES cipher using the provided key
    block, err := aes.NewCipher(encryptionKey)
    if err != nil {
        return nil, fmt.Errorf("failed to create cipher: %w", err)
    }
    
    // Create a GCM mode instance for authenticated encryption
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, fmt.Errorf("failed to create GCM: %w", err)
    }
    
    return &EncryptedAuditLogger{
        auditLogger: &SecureAuditLogger{auditFile: auditFile},
        block:       block,
        gcm:         gcm,
    }, nil
}

func (eal *EncryptedAuditLogger) LogEncryptedAuditEvent(eventType, actor, action, resource, outcome string, details map[string]interface{}) error {
    auditEvent := AuditEvent{
        Timestamp: time.Now(),
        EventType: eventType,
        Actor:     actor,
        Action:    action,
        Resource:  resource,
        Outcome:   outcome,
        Details:   eal.auditLogger.config.ApplyFilters(
            eal.auditLogger.sanitizer.SanitizeStruct(details),
        ).(map[string]interface{}),
    }
    
    // Serialize the audit event
    data, err := json.Marshal(auditEvent)
    if err != nil {
        return fmt.Errorf("failed to serialize audit event: %w", err)
    }
    
    // Generate a random nonce for encryption
    nonce := make([]byte, eal.gcm.NonceSize())
    if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
        return fmt.Errorf("failed to generate nonce: %w", err)
    }
    
    // Encrypt the data
    encryptedData := eal.gcm.Seal(nonce, nonce, data, nil)
    
    // Write encrypted data to file
    return eal.writeEncryptedLog(encryptedData)
}

func (eal *EncryptedAuditLogger) writeEncryptedLog(encryptedData []byte) error {
    // Write to encrypted audit log file
    file, err := os.OpenFile(eal.auditLogger.auditFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
    if err != nil {
        return fmt.Errorf("failed to open encrypted audit log file: %w", err)
    }
    defer file.Close()
    
    // Write encrypted data in a format that includes metadata for decryption
    logEntry := fmt.Sprintf("%x\n", encryptedData)
    _, err = file.WriteString(logEntry)
    return err
}

func (eal *EncryptedAuditLogger) DecryptLogEntry(encryptedHex string) ([]byte, error) {
    // Convert hex string back to bytes
    encryptedData, err := hex.DecodeString(encryptedHex)
    if err != nil {
        return nil, fmt.Errorf("failed to decode hex: %w", err)
    }
    
    // Extract nonce
    nonceSize := eal.gcm.NonceSize()
    if len(encryptedData) < nonceSize {
        return nil, fmt.Errorf("encrypted data too short")
    }
    
    nonce, ciphertext := encryptedData[:nonceSize], encryptedData[nonceSize:]
    
    // Decrypt the data
    decryptedData, err := eal.gcm.Open(nil, nonce, ciphertext, nil)
    if err != nil {
        return nil, fmt.Errorf("failed to decrypt: %w", err)
    }
    
    return decryptedData, nil
}

Implementation Integration

Integration with Existing Logging

type SecureLogger struct {
    baseLogger  *Logger
    sanitizer   *LogSanitizer
    config      *LogConfig
    auditLogger *EncryptedAuditLogger
}

func (sl *SecureLogger) Log(level, msg string, keyvals ...interface{}) error {
    // Apply sanitization to the message
    sanitizedMsg := sl.sanitizer.Sanitize(msg)
    
    // Apply sanitization to key-value pairs
    sanitizedKeyvals := make([]interface{}, len(keyvals))
    for i := 0; i < len(keyvals); i++ {
        if i%2 == 0 {
            sanitizedKeyvals[i] = keyvals[i]  // Keys are usually safe
        } else {
            sanitizedKeyvals[i] = sl.sanitizer.SanitizeStruct(keyvals[i])
        }
    }
    
    // Log the sanitized data
    return sl.baseLogger.Log(level, sanitizedMsg, sanitizedKeyvals...)
}

Testing Strategy

  • Unit tests for sanitization functions
  • Integration tests with sensitive data
  • Audit logging format validation
  • Encryption/decryption functionality tests
  • Performance testing for sanitization overhead

Code Review Checklist

  • All sensitive data is properly sanitized before logging
  • Configurable log filtering is implemented
  • Secure audit logging format is used
  • Log encryption is properly implemented for sensitive trails
  • Error handling is consistent and secure
  • Performance impact of sanitization is minimal
  • Tests cover all sanitization scenarios

Rollback Strategy

If issues arise after deployment:

  1. Temporarily disable enhanced sanitization
  2. Revert to basic logging with minimal sanitization
  3. Monitor for any logging-related issues

Success Metrics

  • Zero sensitive data in plain text in logs
  • All audit logs properly formatted and sanitized
  • Encrypted audit logs successfully decrypted when needed
  • No performance degradation beyond acceptable limits
  • All logging tests pass consistently