Skip to main content

Overview

This vulnerability occurs when an application stores sensitive data (such as passwords, credit card numbers, API keys, personal information, session identifiers) in plain text (unencrypted) in long-term storage locations like databases, configuration files, log files, backups, or even source code repositories. If an attacker gains access to this storage (e.g., through SQL Injection, server misconfiguration, backup theft, leaked source code), the sensitive data is immediately compromised. 💾🔓

Business Impact

Storing sensitive data in cleartext is a major security failure that can lead to:
  • Massive Data Breaches: An attacker gaining access to the storage gets all the sensitive data directly.
  • Account Takeover: If passwords or session tokens are stored in cleartext, attacker gains immediate access to user accounts.
  • Identity Theft and Fraud: Exposed PII or financial data can be used for malicious purposes.
  • Compliance Violations: Storing sensitive data unencrypted violates regulations like PCI-DSS, GDPR, HIPAA, leading to severe fines and legal action.
  • Reputational Damage: Breaches resulting from cleartext storage severely damage user trust and brand reputation.

Reference Details

CWE ID: CWE-312 (Related: CWE-256, CWE-313, CWE-316) OWASP Top 10 (2021): A04:2021 - Insecure Design (Failure to protect data at rest) & A02:2021 - Cryptographic Failures Severity: High to Critical

Framework-Specific Analysis and Remediation

This is a design and implementation flaw. Never store sensitive data in cleartext. Frameworks provide tools for secure storage, but developers must use them correctly. Key Remediation Principles:
  1. Hashing for Passwords: Never store passwords. Store strong, salted hashes using modern algorithms (bcrypt, Argon2, PBKDF2). See CWE-916 and CWE-759.
  2. Encryption for Other Sensitive Data: Encrypt data like API keys, PII, health information, or connection strings using strong, standard algorithms (like AES-GCM).
  3. Secure Key Management: Protect the encryption keys themselves. Do not hard-code them; use environment variables, secrets managers (Vault, KMS, Key Vault), or HSMs. See CWE-321.
  4. Data Minimization: Don’t store sensitive data if you don’t absolutely need it. If you only need to verify PII, consider hashing it instead of storing it raw.
  5. Secure Logging: Configure logging frameworks to avoid logging sensitive data (passwords, session tokens, credit card numbers) in cleartext. Mask or filter sensitive fields.
  6. Secure Backups: Ensure database backups are encrypted.

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

Framework Context

Storing passwords directly in Django User models, saving API keys or PII unencrypted in database fields, or logging sensitive data.

Vulnerable Scenario 1: Storing Plaintext Password

A custom user model saves the password directly.
# models.py (Custom User)
class LegacyUser(models.Model):
    username = models.CharField(max_length=150, unique=True)
    # DANGEROUS: Password stored directly in the database.
    password_cleartext = models.CharField(max_length=128)

    def save(self, *args, **kwargs):
        # No hashing is performed before saving.
        super().save(*args, **kwargs)

Vulnerable Scenario 2: Storing API Key in Database Field

# models.py (Service Integration)
class ServiceConfig(models.Model):
    service_name = models.CharField(max_length=100)
    # DANGEROUS: API key stored unencrypted.
    api_key_cleartext = models.CharField(max_length=200)
    # ... other config ...

Mitigation and Best Practices

  • Use Django’s built-in User model or AbstractUser which handles password hashing automatically (user.set_password()).
  • Use libraries like django-cryptography or implement encryption using cryptography (Fernet, AES-GCM) before saving sensitive fields to the database. Load the encryption key securely (see CWE-321).
  • Configure logging filters to mask sensitive fields.

Secure Code Example

# models.py (Secure Password Hashing - Using AbstractUser)
from django.contrib.auth.models import AbstractUser

class SecureUser(AbstractUser):
    # SECURE: Inherits secure password handling from Django.
    # `password` field stores salted hash automatically via set_password().
    pass

# models.py (Secure API Key Storage - Example using django-cryptography)
# Requires pip install django-cryptography
from cryptography.fernet import Fernet
from django_cryptography.fields import EncryptedCharField
import os

# SECURE: Key loaded from environment (NEVER hardcode)
# key = os.environ.get('FIELD_ENCRYPTION_KEY') # Ensure this is set
# fernet = Fernet(key.encode()) # Requires a valid Fernet key

class SecureServiceConfig(models.Model):
    service_name = models.CharField(max_length=100)
    # SECURE: Field encrypted at rest using AES.
    # Requires proper key management for the FERNET_KEY.
    api_key_encrypted = EncryptedCharField(max_length=500) # Length increases due to encryption/encoding
    # ... other config ...

Testing Strategy

Inspect the database directly. Check password fields (should be long hashes, not readable passwords). Check fields storing API keys, tokens, PII – they should be encrypted (appear as random-looking Base64 or binary data). Review log files for sensitive data. Check configuration files (settings.py) for cleartext secrets.