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. 💾🔓
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
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:
Hashing for Passwords:Never store passwords. Store strong, salted hashes using modern algorithms (bcrypt, Argon2, PBKDF2). See CWE-916 and CWE-759.
Encryption for Other Sensitive Data: Encrypt data like API keys, PII, health information, or connection strings using strong, standard algorithms (like AES-GCM).
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.
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.
Secure Logging: Configure logging frameworks to avoid logging sensitive data (passwords, session tokens, credit card numbers) in cleartext. Mask or filter sensitive fields.
Secure Backups: Ensure database backups are encrypted.
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.
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.
Use Spring Security’s PasswordEncoder to hash passwords before saving the User entity. Store only the hash.
Use JPA Attribute Converters or libraries like jasypt-spring-boot to automatically encrypt/decrypt sensitive fields (API keys, PII) when saving/loading entities. Load the encryption key securely.
Configure logging framework (Logback, Log4j2) filters or use custom formatting to mask sensitive data patterns (credit cards, SSNs) or specific fields in log messages.
// model/User.java (Secure - Stores Hash)@Entitypublic class User { // ... id, username ... // SECURE: Store the hashed password. private String passwordHash; // NO plainPassword field! // ... getters/setters for passwordHash ...}// service/UserService.java (Secure Hashing)@Servicepublic class UserService { @Autowired private PasswordEncoder passwordEncoder; @Autowired private UserRepository userRepository; public User registerUser(String username, String rawPassword) { User user = new User(); user.setUsername(username); // SECURE: Hash password before saving. user.setPasswordHash(passwordEncoder.encode(rawPassword)); return userRepository.save(user); }}// model/Config.java (Secure Encryption using Attribute Converter - Conceptual)@Entitypublic class Config { @Id private Long id; // SECURE: Apply converter to encrypt/decrypt this field automatically. @Convert(converter = AesCryptoConverter.class) private String sensitiveApiKey;}// Need to implement AesCryptoConverter using javax.crypto.Cipher// and SECURELY manage the encryption key used by the converter.// service/PaymentService.java (Secure Logging)public class PaymentService { private static final Logger log = LoggerFactory.getLogger(PaymentService.class); public void processPayment(String creditCardNumber, String cvv, ...) { // SECURE: Mask sensitive data before logging. String maskedCard = maskCardNumber(creditCardNumber); // Implement masking logic log.info("Processing payment for card ending in: {}", maskedCard); // Log only masked data // DO NOT log CVV at all (PCI-DSS compliance) // ... processing logic ... } // Implement maskCardNumber appropriately (e.g., show last 4 digits)}
Inspect the database directly. Check password columns (should be hashes). Check columns with API keys, PII (should be encrypted). Review application log files (.log) for any cleartext passwords, tokens, credit card numbers, etc.
Storing plaintext passwords in IdentityUser or custom user tables, saving sensitive data unencrypted in database columns, logging sensitive info via ILogger.
// Models/LegacyUser.cspublic class LegacyUser{ public int Id { get; set; } public string Username { get; set; } // DANGEROUS: Property to store password directly. public string ClearTextPassword { get; set; }}// Assume DbContext saves this property directly.
Vulnerable Scenario 2: Logging Request Body Containing Secrets
// Middleware/LoggingMiddleware.cspublic class LoggingMiddleware{ private readonly RequestDelegate _next; private readonly ILogger<LoggingMiddleware> _logger; public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger) { /* ... */ } public async Task InvokeAsync(HttpContext context) { context.Request.EnableBuffering(); // Allow reading body multiple times var reader = new StreamReader(context.Request.Body); var body = await reader.ReadToEndAsync(); // DANGEROUS: Logging the raw request body might include passwords, API keys, etc. _logger.LogInformation("Request Body: {RequestBody}", body); context.Request.Body.Position = 0; // Reset stream position await _next(context); }}
Use ASP.NET Core Identity’s UserManager<TUser> which handles password hashing. Store only the PasswordHash.
Encrypt sensitive data in the database. Options include SQL Server Always Encrypted, application-level encryption using System.Security.Cryptography (managing keys securely), or ORM extensions.
Configure logging to exclude or mask sensitive fields. Avoid logging raw request/response bodies containing sensitive data.
// Models/ApplicationUser.cs (Secure - using Identity)using Microsoft.AspNetCore.Identity;// SECURE: Inherits from IdentityUser which manages PasswordHash securely.public class ApplicationUser : IdentityUser{ // Add custom properties if needed, but NOT password.}// Service saving data (Secure Hashing via UserManager)// private readonly UserManager<ApplicationUser> _userManager;// ...// var user = new ApplicationUser { UserName = model.Email, Email = model.Email };// var result = await _userManager.CreateAsync(user, model.Password); // Hashes password// Models/Settings.cs (Secure Encryption - conceptual using AES)public class Settings{ public int Id { get; set; } // Store encrypted value, e.g., as Base64 string or byte[] public string EncryptedApiKey { get; set; } // Use a service to handle encryption/decryption, managing keys securely [NotMapped] // Tell EF not to map this property directly public string ApiKey { get => EncryptionService.Decrypt(EncryptedApiKey); // Needs secure key management set => EncryptedApiKey = EncryptionService.Encrypt(value); }}// Middleware/LoggingMiddleware.cs (Secure Logging)public async Task InvokeAsync(HttpContext context){ // SECURE: Avoid logging raw body for sensitive routes. // Or implement robust filtering/masking logic if body logging is essential. if (context.Request.Path.StartsWithSegments("/api/auth")) // Example check { _logger.LogInformation("Processing sensitive request to {Path}", context.Request.Path); // DO NOT log body } else { // Log body safely if needed (e.g., using filtering) } await _next(context);}
Use Laravel’s Hash::make() before saving passwords to the password column (which should store the hash).
Encrypt sensitive configuration or model attributes using Crypt::encryptString() before saving, and Crypt::decryptString() upon retrieval. Ensure APP_KEY is secure. Consider database-level encryption if available.
Configure Monolog (via config/logging.php) to add processors or formatters that mask sensitive keys (like password, token, credit_card) in log context arrays. Avoid logging $request->all().
Vulnerable Scenario 2: Logging User Object with Sensitive Data
# app/controllers/users_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) # DANGEROUS: If User model has sensitive attributes (e.g., token, # api_key) and the logger's default formatter outputs all attributes. Rails.logger.info "Showing user: #{@user.inspect}" render :show endend
Use has_secure_password in your model to handle password hashing (bcrypt).
Use attr_encrypted gem or Rails encrypted attributes (newer versions) to encrypt sensitive model attributes. Manage keys via Rails credentials or environment variables.
Configure Rails logging (config.filter_parameters) in config/initializers/filter_parameter_logging.rb to prevent sensitive parameters (like :password, :token) from being logged. Avoid logging full objects via .inspect if they contain sensitive data; log specific safe attributes.