- 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>
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:
- Temporarily disable enhanced sanitization
- Revert to basic logging with minimal sanitization
- 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