/** * Data Sanitization Utility * CWE-532: Prevents logging of sensitive data * Ensures compliance with HIPAA, PCI, SOX regulations */ const SENSITIVE_FIELDS = [ 'password', 'newPassword', 'oldPassword', 'currentPassword', 'confirmPassword', 'token', 'accessToken', 'refreshToken', 'jwt', 'secret', 'apiKey', 'api_key', 'privateKey', 'private_key', 'two_factor_secret', 'twoFactorSecret', 'backup_codes', 'backupCodes', 'creditCard', 'credit_card', 'cvv', 'ssn', 'social_security', 'pin', 'authCode', 'auth_code' ]; /** * Sanitize object by removing or masking sensitive fields * @param {Object} data - Object to sanitize * @param {Array} additionalFields - Additional fields to sanitize * @returns {Object} Sanitized object */ function sanitizeForLogging(data, additionalFields = []) { if (!data || typeof data !== 'object') { return data; } const sensitiveFields = [...SENSITIVE_FIELDS, ...additionalFields]; const sanitized = Array.isArray(data) ? [] : {}; for (const [key, value] of Object.entries(data)) { const lowerKey = key.toLowerCase(); const isSensitive = sensitiveFields.some(field => lowerKey.includes(field.toLowerCase()) ); if (isSensitive) { sanitized[key] = '[REDACTED]'; } else if (value && typeof value === 'object') { sanitized[key] = sanitizeForLogging(value, additionalFields); } else { sanitized[key] = value; } } return sanitized; } /** * Sanitize user object for export (remove password hash) * @param {Object} user - User object from database * @returns {Object} Sanitized user object */ function sanitizeUserForExport(user) { if (!user) return user; const sanitized = { ...user }; delete sanitized.password; delete sanitized.two_factor_secret; delete sanitized.backup_codes; return sanitized; } /** * Sanitize user array for export * @param {Array} users - Array of user objects * @returns {Array} Sanitized user array */ function sanitizeUsersForExport(users) { if (!Array.isArray(users)) return users; return users.map(user => sanitizeUserForExport(user)); } /** * Mask token for logging (show only last 8 characters) * @param {String} token - Token to mask * @returns {String} Masked token */ function maskToken(token) { if (!token || typeof token !== 'string') return '[INVALID_TOKEN]'; if (token.length <= 8) return '***'; return '...' + token.slice(-8); } /** * Mask email for logging (show only domain) * @param {String} email - Email to mask * @returns {String} Masked email */ function maskEmail(email) { if (!email || typeof email !== 'string') return '[INVALID_EMAIL]'; const parts = email.split('@'); if (parts.length !== 2) return '[INVALID_EMAIL]'; return `***@${parts[1]}`; } /** * Sanitize request body for logging * @param {Object} body - Request body * @returns {Object} Sanitized body */ function sanitizeRequestBody(body) { return sanitizeForLogging(body); } /** * Create safe metadata object for audit logging * Ensures no sensitive data is included in audit logs * @param {Object} data - Data to include in audit metadata * @returns {Object} Safe metadata object */ function createSafeAuditMetadata(data) { const safe = sanitizeForLogging(data); // Specifically handle common patterns if (safe.user && typeof safe.user === 'object') { safe.user = sanitizeUserForExport(safe.user); } if (safe.changes && typeof safe.changes === 'object') { safe.changes = sanitizeForLogging(safe.changes); } return safe; } module.exports = { sanitizeForLogging, sanitizeUserForExport, sanitizeUsersForExport, maskToken, maskEmail, sanitizeRequestBody, createSafeAuditMetadata, SENSITIVE_FIELDS };