Self-generated Error Message Containing Sensitive Information

Description

Self-generated Error Message Containing Sensitive Information is a vulnerability that occurs when a product identifies an error condition and creates its own diagnostic or error messages that contain sensitive information. Unlike error messages generated by external components such as interpreters or databases, these messages are explicitly constructed by the application's own code. The sensitive information may include file system paths, internal variable values, configuration details, database connection strings, user credentials, or stack traces. This weakness typically arises when developers include detailed debugging information in error handlers without considering that these messages may be visible to unauthorized users in production environments.

Risk

Self-generated error messages containing sensitive information create significant security risks by exposing internal system details to potential attackers. Detailed error messages revealing file paths enable path traversal attacks and help attackers understand the application's directory structure. Stack traces and variable dumps expose code logic, function names, and potentially sensitive data values. Configuration details in error messages may reveal database credentials, API keys, or internal network addresses. This information disclosure transforms blind attacks into targeted ones, as attackers can use the revealed details to craft specific exploits for the identified software versions, configurations, or file structures. In multi-tenant environments, error messages may inadvertently leak information about other users or tenants.

Solution

Implement a centralized error handling mechanism that separates internal diagnostic logging from user-facing error messages. Create generic, user-friendly error messages that provide guidance without revealing system internals. Log detailed error information including stack traces and variable values to secure server-side logs accessible only to administrators and developers. Configure production environments to display minimal error information while development environments can show full details. Review all error handling code to ensure sensitive information is never included in messages sent to clients. Implement error message templates that automatically strip potentially sensitive content. Test error handling paths with security scanning tools to identify information leakage before deployment.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Attackers can read sensitive application data through detailed error messages. File paths, internal states, configuration values, and other system details may be exposed, enabling further attacks.

Example Code

Vulnerable Code (Python)

The following code demonstrates a vulnerable error handler that exposes sensitive system information:

import traceback
import os
from flask import Flask, jsonify

app = Flask(__name__)

# Sensitive configuration
DATABASE_URL = "postgresql://admin:[email protected]:5432/production"
API_KEY = "sk-live-abc123secretkey456"

def load_user_config(user_id):
    config_path = f"/etc/myapp/users/{user_id}/config.json"
    with open(config_path, 'r') as f:
        return f.read()

@app.route('/api/user/<user_id>/config')
def get_user_config(user_id):
    try:
        config = load_user_config(user_id)
        return jsonify({"config": config})
    except FileNotFoundError as e:
        # Vulnerable: Exposes full file path
        return jsonify({
            "error": "Configuration file not found",
            "details": f"Cannot open file: {e.filename}",
            "path": f"/etc/myapp/users/{user_id}/config.json"
        }), 404
    except Exception as e:
        # Vulnerable: Exposes stack trace and internal details
        return jsonify({
            "error": "Internal server error",
            "exception_type": type(e).__name__,
            "message": str(e),
            "stack_trace": traceback.format_exc(),
            "database_url": DATABASE_URL,  # Critical exposure!
            "working_directory": os.getcwd(),
            "python_path": os.environ.get('PYTHONPATH', '')
        }), 500

@app.route('/api/connect')
def connect_database():
    try:
        # Database connection attempt
        raise ConnectionError("Connection refused")
    except Exception as e:
        # Vulnerable: Exposes credentials in error
        return jsonify({
            "error": f"Failed to connect to {DATABASE_URL}",
            "api_key_status": f"Key {API_KEY[:10]}... is valid"
        }), 500

The code exposes file paths, database credentials, API keys, stack traces, and environment variables in error responses.

Fixed Code (Python)

import traceback
import logging
import uuid
from flask import Flask, jsonify

app = Flask(__name__)

# Configure secure logging
logging.basicConfig(
    filename='/var/log/myapp/errors.log',
    level=logging.ERROR,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Generic error messages for users
ERROR_MESSAGES = {
    'not_found': "The requested resource could not be found.",
    'internal': "An internal error occurred. Please try again later.",
    'unauthorized': "You are not authorized to access this resource.",
    'invalid_input': "The provided input is invalid."
}

def generate_error_id():
    """Generate unique error ID for support reference"""
    return str(uuid.uuid4())[:8]

def load_user_config(user_id):
    config_path = f"/etc/myapp/users/{user_id}/config.json"
    with open(config_path, 'r') as f:
        return f.read()

@app.route('/api/user/<user_id>/config')
def get_user_config(user_id):
    try:
        config = load_user_config(user_id)
        return jsonify({"config": config})

    except FileNotFoundError as e:
        error_id = generate_error_id()

        # Log detailed information internally
        logger.error(
            f"Error ID: {error_id} - Config file not found for user {user_id}. "
            f"Path: {e.filename}"
        )

        # Return generic message to user
        return jsonify({
            "error": ERROR_MESSAGES['not_found'],
            "error_id": error_id,
            "support_message": "If this issue persists, contact support with the error ID."
        }), 404

    except Exception as e:
        error_id = generate_error_id()

        # Log full details internally (never exposed to users)
        logger.error(
            f"Error ID: {error_id} - Unhandled exception in get_user_config\n"
            f"User ID: {user_id}\n"
            f"Exception: {type(e).__name__}: {str(e)}\n"
            f"Stack trace:\n{traceback.format_exc()}"
        )

        # Return generic message to user
        return jsonify({
            "error": ERROR_MESSAGES['internal'],
            "error_id": error_id
        }), 500

@app.errorhandler(500)
def handle_500(error):
    """Global handler ensures no sensitive data leaks"""
    error_id = generate_error_id()
    logger.error(f"Error ID: {error_id} - Unhandled 500 error: {error}")
    return jsonify({
        "error": ERROR_MESSAGES['internal'],
        "error_id": error_id
    }), 500

The fix uses generic error messages for users while logging detailed diagnostics to secure server-side logs. Error IDs link user reports to detailed internal logs.


Exploited in the Wild

ASP.NET Detailed Error Pages (Multiple Organizations, 2000s-Present)

ASP.NET applications with customErrors disabled in production exposed detailed stack traces and configuration information through self-generated error pages. These error messages revealed database connection strings, file paths, and code structure. Attackers used this information to identify vulnerable components and plan targeted attacks. Microsoft eventually changed default configurations to prevent this exposure.

Laravel Debug Mode Exposure (Multiple Organizations, 2021)

Thousands of Laravel applications were discovered running with APP_DEBUG=true in production, causing the framework to generate detailed error pages containing environment variables, database credentials, and API keys. Security researchers found exposed secrets including AWS credentials and payment gateway keys. This led to a coordinated disclosure effort and increased awareness about secure configuration management.


Tools to Test/Exploit

  • Burp Suite — Web security testing platform that can trigger and analyze error responses to identify sensitive information disclosure.

  • OWASP ZAP — Open-source scanner with active scanning capabilities to detect information leakage in error messages.

  • Nikto — Web server scanner that tests for error page information disclosure and debug mode detection.


CVE Examples

  • CVE-2005-1745 — Information leak revealed sensitive data through detailed error messages accessible with physical system access.

  • CVE-2018-1000129 — Jolokia exposed sensitive system properties and environment variables through error messages.

  • CVE-2021-22986 — F5 BIG-IP exposed internal configuration details through self-generated error responses.


References

  1. MITRE Corporation. "CWE-210: Self-generated Error Message Containing Sensitive Information." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/210.html

  2. OWASP Foundation. "Improper Error Handling." OWASP. https://owasp.org/www-community/Improper_Error_Handling

  3. OWASP Foundation. "Error Handling Cheat Sheet." OWASP Cheat Sheet Series. https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html