13 KiB
Error Handling and Logging Security Implementation
Overview
This document describes the comprehensive error handling and logging security implementation that addresses CWE-209: Information Exposure Through Error Messages. The system ensures that sensitive information such as file paths, stack traces, database details, and system internals are never exposed to end users.
Security Objectives
- Prevent Information Disclosure: Sanitize all error messages before sending to clients
- Secure Logging: Log full error details internally while exposing safe messages externally
- User-Friendly Messages: Provide meaningful feedback without technical details
- Audit Trail: Maintain comprehensive logs for security monitoring and debugging
Implementation Components
Backend Security
0. Process-Level Error Handlers (backend/server.js)
CWE-391 Compliance:
- ✅ Catches all uncaught exceptions
- ✅ Handles unhandled promise rejections
- ✅ Graceful shutdown on SIGTERM/SIGINT
- ✅ Server error handling
- ✅ Logs all errors before exit
Handlers Implemented:
process.on('uncaughtException', handler) // Catches sync exceptions
process.on('unhandledRejection', handler) // Catches async rejections
process.on('SIGTERM', handler) // Graceful shutdown
process.on('SIGINT', handler) // Ctrl+C handling
server.on('error', handler) // Server startup errors
Backend Security
1. Error Handler Utility (backend/utils/errorHandler.js)
Features:
- Sanitizes error messages before client responses
- Removes file paths, stack traces, and system information
- Maps technical errors to user-friendly messages
- Detects and filters sensitive patterns
- Provides structured error responses
Error Types Handled:
- Authentication & Authorization errors
- Database constraint violations
- File system errors (ENOENT, EACCES, ENOSPC)
- Network errors (ECONNREFUSED, ETIMEDOUT, ENOTFOUND)
- Validation errors
- Rate limiting
Key Functions:
sanitizeError(error, defaultMessage) // Sanitizes error for client
logError(error, context) // Logs full error internally
errorMiddleware(err, req, res, next) // Express middleware
asyncHandler(fn) // Wraps async routes
ErrorResponses.* // Standard error creators
2. Enhanced Logger (backend/utils/logger.js)
Security Features:
- Automatically redacts passwords, tokens, secrets, and API keys
- Separates error logs from combined logs
- Supports production and development formats
- File rotation (5MB files, keep 5 backups)
- Structured JSON logging for analysis
Sensitive Data Redaction:
// Automatically redacts:
- "password": "[REDACTED]"
- "token": "[REDACTED]"
- "secret": "[REDACTED]"
- "apiKey": "[REDACTED]"
- "authorization": "Bearer [REDACTED]"
- "privateKey": "[REDACTED]"
Additional Helpers:
logger.security(action, details) // Security event logging
logger.performance(operation, duration) // Performance monitoring
3. Global Error Middleware (backend/server.js)
Integrated into Express application as the last middleware:
- Catches all unhandled errors
- Logs full details internally with context
- Returns sanitized responses to clients
- Includes timestamp and error code
Frontend Security
0. Window-Level Error Handlers (frontend/src/main.jsx)
CWE-391 Compliance:
- ✅ Catches all window errors
- ✅ Handles unhandled promise rejections
- ✅ Service worker error handling
- ✅ Prevents default browser error display
Handlers Implemented:
window.addEventListener('error', handler) // Global errors
window.addEventListener('unhandledrejection', handler) // Promise rejections
Service Worker Protection: (frontend/public/service-worker.js)
self.addEventListener('error', handler) // SW errors
self.addEventListener('unhandledrejection', handler) // SW rejections
1. Error Handler Utility (frontend/src/utils/errorHandler.js)
Features:
- Extracts user-friendly messages from API responses
- Classifies errors by type (auth, permission, validation, network, server)
- Determines error severity
- Provides retry logic for transient failures
- Never exposes technical details to UI
Key Functions:
getErrorMessage(error, defaultMessage) // Extract safe message
isAuthError(error) // Check if auth error
isPermissionError(error) // Check if permission error
isValidationError(error) // Check if validation error
isNetworkError(error) // Check if network error
getErrorType(error) // Classify error type
formatError(error, options) // Format for display
createErrorNotification(error, options) // Create notification
retryRequest(fn, options) // Retry with backoff
2. Error Boundary Component (frontend/src/components/ErrorBoundary.jsx)
Purpose:
- Catches JavaScript errors in React component tree
- Prevents application crashes
- Displays user-friendly fallback UI
- Provides recovery options (reset, reload)
- Does NOT expose stack traces to users
Features:
- Automatic error counting
- Reset functionality
- Full page reload option
- Localized messages
3. Error Notification Provider (frontend/src/components/ErrorNotificationProvider.jsx)
Global Notification System:
- Context-based notification management
- Automatic error type detection
- Localized error titles and messages
- Severity-based styling (error, warning, info, success)
- Auto-dismiss with configurable duration
Usage:
const { showError, showSuccess, showWarning, showInfo } = useErrorNotification();
// Show error from API response
showError(error, { defaultMessage: 'Custom message' });
// Show success message
showSuccess('Operation completed successfully');
4. Enhanced API Client (frontend/src/utils/api.js)
Security Improvements:
- Automatic error handling with sanitization
- Timeout configuration (30 seconds)
- Automatic retry for transient failures
- Auth error detection and redirect
- Silent token parsing errors
- Development-only error logging
Internationalization
Error Message Translations
English (frontend/src/locales/en.json):
"errors": {
"general": { "unexpected", "tryAgain", "contactSupport" },
"network": { "title", "message", "timeout", "offline" },
"auth": { "title", "required", "invalid", "failed", "sessionExpired" },
"permission": { "title", "message", "adminRequired", "contactAdmin" },
"validation": { "title", "invalidInput", "requiredField", "invalidFormat" },
"server": { "title", "message", "unavailable", "maintenance", "overloaded" },
"notFound": { "title", "message", "page", "resource" },
"conflict": { "title", "message", "duplicate", "outdated" },
"rateLimit": { "title", "message", "slowDown" }
}
Romanian (frontend/src/locales/ro.json):
Full translations provided for all error categories.
Security Benefits
1. CWE-209 Mitigation
Before:
// Exposed internal details
res.status(500).json({ error: error.message });
// User sees: "ENOENT: no such file or directory, open '/app/data/db/users.db'"
After:
// Sanitized message
const sanitized = sanitizeError(error);
res.status(500).json({ error: sanitized.message });
// User sees: "An internal error occurred"
2. Stack Trace Protection
Before:
Error: Database error
at /app/backend/routes/users.js:45:12
at processTicksAndRejections (internal/process/task_queues.js:93:5)
After:
{
"error": "Database operation failed",
"code": "DATABASE_ERROR",
"timestamp": "2025-12-15T10:30:00.000Z"
}
3. Sensitive Data Redaction
Logs automatically redact:
- Passwords
- Authentication tokens
- API keys
- Secrets
- Private keys
- Authorization headers
4. Contextual Logging
Internal logs include:
- Full error stack trace
- Request method and path
- User ID (if authenticated)
- IP address
- Timestamp
- Additional context
Client responses include:
- Safe error message
- Error code
- Timestamp
- HTTP status code
Usage Examples
Backend Route with Error Handling
const { asyncHandler, ErrorResponses } = require('../utils/errorHandler');
router.get('/users/:id', asyncHandler(async (req, res) => {
const user = await findUser(req.params.id);
if (!user) {
throw ErrorResponses.notFound('User not found');
}
res.json(user);
}));
Frontend Component with Error Handling
import { useErrorNotification } from '../components/ErrorNotificationProvider';
import { getErrorMessage } from '../utils/errorHandler';
function MyComponent() {
const { showError, showSuccess } = useErrorNotification();
const handleSubmit = async () => {
try {
await api.post('/users', data);
showSuccess('User created successfully');
} catch (error) {
showError(error);
}
};
}
Custom Error Messages
// Backend
throw ErrorResponses.badRequest('Email address is already in use');
// Frontend automatically displays localized message
// No technical details exposed
Testing
Test Cases
-
Database Errors
- UNIQUE constraint → "Duplicate entry exists"
- NOT NULL constraint → "Required field is missing"
- Foreign key constraint → "Resource conflict"
-
File System Errors
- ENOENT → "File not found"
- EACCES → "Access forbidden"
- ENOSPC → "Service temporarily unavailable"
-
Network Errors
- ECONNREFUSED → "External service unavailable"
- ETIMEDOUT → "Request timeout"
- ENOTFOUND → "Network request failed"
-
Authentication Errors
- Invalid token → "Invalid or expired authentication token"
- Missing auth → "Authentication required"
- Expired session → "Your session has expired"
Manual Testing
# Test error sanitization
curl http://localhost:12345/api/nonexistent
# Should return: {"error": "Resource not found", ...}
# Should NOT expose file paths or stack traces
# Test authentication error
curl http://localhost:12345/api/users
# Should return: {"error": "Authentication required", ...}
# Test rate limiting
# Make 100+ rapid requests
# Should return: {"error": "Too many requests. Please try again later", ...}
Monitoring and Maintenance
Log Files
Location: /app/logs/
error.log- Error-level events onlycombined.log- All application logs
Rotation: 5MB per file, keep 5 files
Security Events
Monitor for:
- Unusual error patterns
- Repeated authentication failures
- Rate limit violations
- Permission denied attempts
- Database constraint violations
Performance Monitoring
const start = Date.now();
await performOperation();
logger.performance('operation_name', Date.now() - start);
Docker Integration
All changes are automatically included in Docker builds:
# Logs directory created with correct permissions
# Error handling utilities bundled
# Frontend error components included
# Translations packaged
PWA & Desktop App Compatibility
- Error boundary works in all environments
- Service worker error handling included
- Electron app error logging configured
- APK builds include error handling
Best Practices
DO:
✅ Use ErrorResponses for standard errors
✅ Use asyncHandler for async routes
✅ Log errors with context using logError()
✅ Use useErrorNotification() in React components
✅ Provide user-friendly error messages
✅ Include error codes for debugging
DON'T:
❌ Never send error.stack to clients
❌ Never expose file paths in error messages
❌ Never include database query details in responses
❌ Never log passwords or tokens
❌ Never use console.error() for sensitive data
❌ Never expose internal implementation details
Compliance
This implementation addresses:
- CWE-209: Information Exposure Through Error Messages ✅
- CWE-391: Unchecked Error Condition ✅
- OWASP A01:2021: Broken Access Control
- OWASP A07:2021: Identification and Authentication Failures
- OWASP A09:2021: Security Logging and Monitoring Failures
Summary
The error handling and logging security implementation provides:
- ✅ Complete CWE-209 mitigation - No information leakage
- ✅ Complete CWE-391 compliance - No unhandled exceptions
- ✅ Secure logging - Full internal logs, safe external messages
- ✅ User-friendly errors - Clear, actionable messages
- ✅ Multi-language support - English and Romanian translations
- ✅ Global error handling - Process, window, and component level
- ✅ Structured logging - JSON format for analysis
- ✅ Automatic sanitization - Passwords, tokens, secrets redacted
- ✅ Docker integration - All changes bundled
- ✅ PWA/Desktop compatible - Works in all environments
- ✅ Service worker protection - Error handling in SW context
- ✅ Production-ready - Tested and documented
All existing features remain functional. No breaking changes introduced.