Skip to main content

Overview

Sensitive Data Exposure occurs when an application unintentionally reveals sensitive information to an unauthorized party. This can include PII, financial data, internal system details, or credentials. This weakness is often the result of misconfiguration (like running in “debug” mode) or failing to filter sensitive data from API responses.

Business Impact

This vulnerability can lead to massive data breaches, loss of user trust, and severe regulatory fines (e.g., under GDPR, CCPA). Leaked system information and stack traces also provide attackers with a detailed map of your application, making other attacks (like Injection or Access Control bypass) much easier.

Reference Details

CWE ID: CWE-200 OWASP Top 10 (2021): A01:2021 - Broken Access Control Severity: Medium

Framework-Specific Analysis and Remediation

All frameworks have a “debug” or “development” mode that is intentionally verbose. The most common vulnerability is a simple failure to disable this mode in production. The second most common is serializing entire data models (like a User object) directly to an API response, which accidentally includes password hashes, tokens, or PII.
  • Python
  • Java
  • .NET(C#)
  • PHP
  • Node.js
  • Ruby

Framework Context

Django’s DEBUG = True setting is the primary culprit. For Django Rest Framework (DRF), ModelSerializer can over-share data if not explicitly configured.

Vulnerable Scenario 1: Debug Mode in Production

Leaving DEBUG = True in settings.py on a production server will show detailed stack traces to the public.
# settings.py
# DANGEROUS: This will leak all settings, stack traces, and more.
DEBUG = True

Vulnerable Scenario 2: Over-sharing in API

A ModelSerializer for the User model that doesn’t restrict fields.
# users/serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        # DANGEROUS: This will serialize ALL fields, including 'password' (hash),
        # 'is_staff', 'is_superuser', and 'date_joined'.
        fields = '__all__'

Mitigation and Best Practices

Set DEBUG = False in production. Use environment variables to control this. For DRF, explicitly list fields using the fields tuple or use exclude to blacklist sensitive ones.

Secure Code Example

Use a DTO (Data Transfer Object) pattern, which DRF serializers provide, to create a “whitelist” of safe fields.
# users/serializers.py (Secure Version)
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        # SECURE: Only the 'id' and 'username' are exposed.
        fields = ('id', 'username', 'email')
        
# Or, using exclude:
class UserAdminSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        # SECURE: Excludes the password hash, even for an admin view.
        exclude = ('password',)

Testing Strategy

Write a test to ensure DEBUG is False. For APIs, write a unit test for the serializer or an integration test for the endpoint and assert that sensitive keys are not in the response.
# users/tests.py
from django.conf import settings

def test_debug_is_off_in_production_settings(self):
    # Assuming you load a 'production.py' settings file for this test
    self.assertFalse(settings.DEBUG)

def test_user_api_does_not_leak_password_hash(self):
    response = self.client.get(reverse('user-detail', args=[self.user.id]))
    self.assertEqual(response.status_code, 200)
    self.assertNotIn('password', response.json())