- 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>
424 lines
13 KiB
Markdown
424 lines
13 KiB
Markdown
# 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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
```go
|
|
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 |