Skip to main content

Overview

This vulnerability occurs when an application logs sensitive data in cleartext to files, the console, or a log management system. This data can include passwords, session tokens, API keys, credit card numbers, personal user information (PII), or detailed debugging information that reveals internal application state. If an attacker gains access to these logs (e.g., through a server misconfiguration (CWE-548), file traversal (CWE-22), or by compromising an administrator’s account), they can easily harvest these secrets. 📜🔑

Business Impact

Storing sensitive data in logs is a critical information disclosure vulnerability:
  • Credential Theft: Leaked passwords or session tokens lead directly to account takeover.
  • Supply Chain Compromise: Leaked API keys can be used to attack third-party services integrated with the application.
  • Massive Data Breaches: Leaked PII or financial data can result in large-scale data breaches.
  • Compliance Violations: Logging sensitive data like credit card numbers or personal health information in cleartext is a major violation of standards like PCI-DSS and HIPAA, leading to severe fines.
  • Hindered Remediation: Even after a breach, if logs contain credentials, attackers might use them to regain access.

Reference Details

CWE ID: CWE-532 OWASP Top 10 (2021): A09:2021 - Security Logging and Monitoring Failures Severity: High

Framework-Specific Analysis and Remediation

This is a common implementation flaw. Developers often log entire objects, request bodies, or exception messages for debugging purposes, forgetting that these may contain sensitive data. Key Remediation Principles:
  1. Never Log Credentials: Ensure passwords, API keys, tokens, and other secrets are never logged in cleartext.
  2. Filter/Mask Sensitive Data: Configure logging frameworks to automatically filter or mask sensitive fields. Most frameworks support this by listing parameter names (e.g., password, token) whose values should be replaced with [FILTERED] or ****.
  3. Do Not Log Full Objects: Avoid logging entire request objects, user objects, or data models. Explicitly log only the specific, non-sensitive properties needed for debugging.
  4. Control Exception Logging: Be careful when logging full exception objects. Ensure toString() methods or exception properties don’t include sensitive data. Log the stack trace, but be wary of exception messages that might contain user input.
  5. Secure Log Storage: Ensure log files themselves are protected with strict file permissions, are not served over HTTP, and are rotated/deleted according to a retention policy.

  • Python
  • Java
  • .NET(C#)
  • PHP
  • Node.js
  • Ruby

Framework Context

Configuring Django’s LOGGING settings or Python’s logging module.

Vulnerable Scenario 1: Logging Full Request (Django)

A custom middleware logs the entire request.POST dictionary, including the password.
# myapp/middleware.py
import logging
logger = logging.getLogger(__name__)

class LogRequestMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.method == 'POST':
            # DANGEROUS: Logs all POST data, including 'password'
            logger.info(f"POST data for {request.path}: {request.POST}")
        response = self.get_response(request)
        return response

Vulnerable Scenario 2: Logging Exception Object

An exception handler logs the full exception, which might contain sensitive details.
# views.py
def some_view(request):
    try:
        # ... code that might fail ...
        perform_action(request.POST['api_key']) # Example
    except Exception as e:
        # DANGEROUS: Logging the full exception 'e' might include
        # the value of 'api_key' if the exception message contains it.
        logger.error(f"Error in some_view: {e}")
        # ...

Mitigation and Best Practices

  • Django: Use django.views.debug.SensitivePostParameters decorator on login/registration views or sensitive_variables to prevent sensitive data from being included in error reports.
  • Logging: In settings.py, configure logging filters (e.g., django.utils.log.CallbackFilter) to filter sensitive keys. Manually filter data before logging.

Secure Code Example

# settings.py (Secure Logging Filter)
from django.utils.log import DEFAULT_LOGGING
import logging

# This filter will be applied to handlers
def sensitive_data_filter(record):
    # Example: Censor 'password' field in log messages
    if isinstance(record.args, dict) and 'password' in record.args:
        record.args['password'] = '****'
    # Add more complex regex filtering for log record.msg if needed
    return True

LOGGING = DEFAULT_LOGGING # Start with defaults
LOGGING['filters'] = {
    'sensitive_data_filter': {
        '()': 'django.utils.log.CallbackFilter',
        'callback': sensitive_data_filter,
    }
}
LOGGING['handlers']['console']['filters'] = ['sensitive_data_filter'] # Apply to console
# Apply filter to file handlers as well

# views.py (Secure Decorator for Error Reports)
from django.views.decorators.debug import sensitive_post_parameters

@sensitive_post_parameters('password', 'password_confirm')
def user_signup(request):
    # SECURE: If this view raises an exception, Django's error reporter
    # will censor 'password' and 'password_confirm' from the report.
    if request.method == 'POST':
        # ...
# myapp/middleware.py (Secure Middleware)
def secure_log_request_middleware(get_response):
    def middleware(request):
        if request.method == 'POST':
            # SECURE: Explicitly copy and filter POST data
            safe_post_data = request.POST.copy()
            if 'password' in safe_post_data:
                safe_post_data['password'] = '****'
            if 'api_key' in safe_post_data:
                safe_post_data['api_key'] = '****'
            logger.info(f"Filtered POST data for {request.path}: {safe_post_data}")
        response = get_response(request)
        return response
    return middleware

Testing Strategy

Submit forms containing sensitive data (login, registration, API key forms). Check application logs (console, files, log aggregator) and error reports (e.g., Django error emails). Verify that sensitive values (password, api_key, credit_card) are masked (e.g., **** or [FILTERED]).