Error Handling and Information Disclosure: Preventing Security Leaks

Error Handling and Information Disclosure: Preventing Security Leaks

Whitespots Team ·
error-handling
information-disclosure
web

Introduction

Poor error handling can leak sensitive information about your application’s internals, helping attackers craft targeted exploits. This guide covers secure error handling practices that protect against information disclosure.

Common Information Disclosure Issues

  • Stack traces exposed to users
  • Database error messages
  • File paths and system information
  • Framework and version details
  • Internal API structure
  • Debug information in production

Vulnerable Error Handling

javascript
// VULNERABLE: Exposes internal details app.post('/api/users', async (req, res) => { try { const user = await db.query('INSERT INTO users...'); res.json(user); } catch (error) { // Leaks database structure and SQL! res.status(500).json({ error: error.message, stack: error.stack }); } });

Secure Error Handling

javascript
// SECURE: Generic errors to users, detailed logs internally const logger = require('./logger'); class AppError extends Error { constructor(message, statusCode, isOperational = true) { super(message); this.statusCode = statusCode; this.isOperational = isOperational; } } app.post('/api/users', async (req, res) => { try { const user = await createUser(req.body); res.json(user); } catch (error) { logger.error('User creation failed', { error: error.message, stack: error.stack, body: req.body, ip: req.ip }); // Generic message to client res.status(500).json({ error: 'Unable to create user. Please try again later.' }); } }); // Global error handler app.use((err, req, res, next) => { logger.error('Application error', { message: err.message, stack: err.stack, url: req.url, method: req.method }); const statusCode = err.statusCode || 500; const message = err.isOperational ? err.message : 'An unexpected error occurred'; res.status(statusCode).json({ error: message, ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) }); });

Input Validation Errors

javascript
// Safe validation error messages const { body, validationResult } = require('express-validator'); app.post('/api/users', body('email').isEmail().withMessage('Invalid email format'), body('password').isLength({ min: 8 }).withMessage('Password too short'), (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { // Safe: only validation messages, no internal details return res.status(400).json({ errors: errors.array().map(e => ({ field: e.param, message: e.msg })) }); } // Continue processing... } );

Production Configuration

javascript
// Environment-specific error handling if (process.env.NODE_ENV === 'production') { // Disable stack traces app.set('env', 'production'); // Remove X-Powered-By header app.disable('x-powered-by'); // Generic error pages app.use((err, req, res, next) => { res.status(err.status || 500); res.json({ error: 'Internal server error' }); }); }

Secure Error Handling Checklist

  • ✅ Never expose stack traces to users
  • ✅ Log detailed errors internally
  • ✅ Return generic error messages
  • ✅ Sanitize validation error messages
  • ✅ Remove server identification headers
  • ✅ Different handling for dev vs production
  • ✅ Avoid exposing file paths
  • ✅ Don’t leak database schema details
  • ✅ Monitor error patterns
  • ✅ Use custom error pages

Conclusion

Secure error handling balances user experience with security by providing helpful feedback without exposing system internals. Implement comprehensive internal logging while presenting generic, safe messages to end users.

Cookie Consent

Our website uses cookies to ensure the best user experience. Cookies help us to:

  • Authorize you

By clicking "Accept All Cookies", you consent to our use of cookies. You can also manage your preferences at any time by visiting our Cookie Settings page.

Learn More Manage Preferences