Skip to content

CWE-312: Cleartext Storage of Sensitive Information - Remediation Guide

In short CWE-312 is sensitive information, such as PII, stored in cleartext in places like databases, configuration files, or logs. Prevent it by omitting sensitive data that is not needed, masking values, and encrypting whatever must be stored.

CWE-312: Cleartext Storage of Sensitive Information occurs when an application stores sensitive information like Personally Identifiable Information (PII) in cleartext. This storage can be in various locations such as databases, configuration files, or logs. Storing sensitive data without proper encryption exposes it to various risks, making it a critical security flaw to address. This article discusses the risks associated with PII exposure due to CWE-312 and provides coding examples in Java, JavaScript, and Python to demonstrate remediation techniques.

  1. Data Theft: Unauthorized access to storage systems can lead to direct theft of PII.

  2. Identity Theft: Exposed PII can be used to impersonate individuals.

  3. Financial Fraud: Sensitive data like credit card details or bank account information can be used for fraudulent transactions.

  1. Reputational Damage: Incidents of data exposure can lead to loss of customer trust and damage to the company’s reputation.

  2. Legal and Regulatory Penalties: Failure to protect data can result in fines and sanctions under laws like GDPR, HIPAA, or CCPA.

  3. Remediation Costs: The cost of addressing a data breach, including incident response and increased security measures, can be substantial.

To mitigate CWE-312, organizations should ensure sensitive data is never stored in cleartext. Techniques include omitting unnecessary sensitive data, masking data to hide true values, and encrypting data to protect its integrity and confidentiality.

Omit sensitive data when it’s not necessary for the application’s functionality.

Java
public class User {
private String username;
// Omit storing sensitive PII such as social security numbers unless absolutely necessary
}
Javascript
function createUser(username) {
// Only store essential information; omit sensitive PII like address or phone number
return { username };
}
Python
class User:
def __init__(self, username):
self.username = username
# Sensitive PII such as date of birth is omitted from storage

When storing data that might identify individuals, mask parts of the data.

Java
public String maskEmail(String email) {
int index = email.indexOf('@');
String localPart = email.substring(0, index);
return localPart.replaceAll(".", "*") + email.substring(index);
}
Javascript
function maskEmail(email) {
let [local, domain] = email.split('@');
local = local.replace(/./g, '*');
return `${local}@${domain}`;
}
Python
def mask_email(email):
local, domain = email.split('@')
masked_local = '*' * len(local)
return f'{masked_local}@{domain}'

Encrypt sensitive data before storage to ensure it is protected from unauthorized access.

Java
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
public class EncryptionUtility {
// secretKey is supplied by the caller, sourced from your KMS or secret store
public static String encrypt(String data, SecretKey secretKey) throws Exception {
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, iv));
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
byte[] payload = ByteBuffer.allocate(iv.length + encryptedData.length).put(iv).put(encryptedData).array();
return java.util.Base64.getEncoder().encodeToString(payload);
}
}
Javascript
const crypto = require('crypto');
// key: 32-byte Buffer loaded from your KMS or secret store
function encrypt(data, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
const encrypted = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
Python
from cryptography.fernet import Fernet
# key: Fernet key loaded from your secret store, never generated per call
def encrypt(data, key):
cipher = Fernet(key)
encrypted_data = cipher.encrypt(data.encode())
return encrypted_data.decode()

HoundDog.ai’s Privacy Code Scanner (hounddog scan) reports CWE-312 when unsanitized sensitive data reaches a storage sink marked risky. It identifies sensitive data elements in source code and traces them through assignments, transformations, string interpolations, and function calls to the sinks they reach.

  • Sensitive data types. The scanner ships with over 100 data element definitions covering common PII, PHI, CHD, PIFI, and secret data (tags PII, PHI, CHD, PIFI, SECRET); the full list is in the scanner’s data-elements.md. A finding names the data element involved, such as Email or Social Security Number.

  • Sinks. CWE-312 is reported on storage-related sinks. The browser Local Storage and Session Storage sinks (localStorage.setItem and its session counterpart) are risky by default. Database, file, configuration file, and cloud storage sinks, such as PostgreSQL, MySQL, AWS S3, and Files, are marked safe by default: dataflows into them are recorded and appear in the Datamap but are not flagged as risky, unless you set the sink to risky under Scanner Rules.

  • Languages. Dataflows are reported for Python, JavaScript, TypeScript, Java, C#/.NET, and Go. Other supported languages are scanned for data elements only and produce no dataflows. See Supported Languages.

  • Sanitization. When AI dataflow reviews are enabled, each dataflow is reviewed with its code and trace in context, including any sanitization logic (masking, hashing, encryption, redaction) applied before the data reaches the sink. Dataflows where the data is effectively sanitized are marked as false positives.

For example, scanning a TypeScript file that writes a Social Security Number to local storage produces a finding like this (console output, excerpt; the file path is shortened):

localStorage.setItem("profile", user.ssn);
🟥 CRITICAL: Social Security Number sent to Local Storage in /path/to/project/app.ts:2:3
2 │ localStorage.setItem("profile", user.ssn)
Associated Compliance Frameworks
────────────────────────────────
CWE: CWE-312
OWASP: A04:2021
Privacy: CCPA, GDPR-A5-32, NIST-800-53

To run a scan, see the quickstart. For how data elements and data sinks are defined and customized, see the scanner rules reference.

Implementing these remediation strategies is crucial for protecting PII from exposure through cleartext storage (CWE-312). Properly handling sensitive information not only prevents data breaches but also ensures compliance with various data protection regulations, thereby maintaining trust and safeguarding against potential financial and reputational harm.