Weakness reference
CWE-311

Missing Encryption of Sensitive Data

This weakness occurs when an application stores or transmits sensitive information—such as passwords, payment card data, API keys, or personal…

01Summary

This weakness occurs when an application stores or transmits sensitive information—such as passwords, payment card data, API keys, or personal identifiers—without encrypting it first. An attacker who gains access to the storage medium or intercepts the transmission can read the data directly, leading to account compromise, fraud, or privacy violations.

02How It Happens

Developers often assume that physical or network security alone will protect sensitive data, or they underestimate the risk of storing plaintext credentials and personal information. This can happen when:

- Data is stored in a database, file, or log without encryption. - Data is transmitted over unencrypted channels (HTTP instead of HTTPS, unencrypted email, or unencrypted API calls). - Encryption is implemented inconsistently—some fields are protected while others are not. - Encryption keys are hardcoded, stored alongside the encrypted data, or not rotated regularly.

The root cause is typically a gap between security requirements and implementation: the developer knows the data is sensitive but doesn't apply encryption as a standard practice.

03Real-World Impact

Unencrypted sensitive data can be exposed through database breaches, server compromise, network interception, or accidental misconfiguration (e.g., a public S3 bucket or unprotected backup file). Once exposed, attackers can use stolen credentials to access user accounts, perform identity theft, commit fraud, or sell the data on underground markets. Regulatory frameworks like GDPR, PCI-DSS, and HIPAA explicitly require encryption of sensitive data at rest and in transit, so this weakness can also result in compliance violations and legal liability.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import sqlite3

def store_user_password(username, password):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    # Password stored in plaintext
    cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)",
                   (username, password))
    conn.commit()
    conn.close()

def send_api_key(api_key):
    import requests
    # Sending API key over unencrypted HTTP
    requests.post('http://example.com/register', data={'key': api_key})

Why it's vulnerable:
Passwords and API keys are stored and transmitted in plaintext, readable by anyone with database or network access.

Fixed pattern
import sqlite3
from cryptography.fernet import Fernet
import requests

# In production, load the key from a secure key management service
encryption_key = Fernet.generate_key()
cipher = Fernet(encryption_key)

def store_user_password(username, password):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    # Hash the password using a proper algorithm (e.g., bcrypt)
    from werkzeug.security import generate_password_hash
    hashed = generate_password_hash(password)
    cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)",
                   (username, hashed))
    conn.commit()
    conn.close()

def send_api_key(api_key):
    # Encrypt sensitive data before storage or transmission
    encrypted_key = cipher.encrypt(api_key.encode())
    # Use HTTPS (not HTTP) for transmission
    requests.post('https://example.com/register', data={'key': encrypted_key})
Vulnerable pattern
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$api_key = $_POST['api_key'];

// Storing password in plaintext
$mysqli = new mysqli('localhost', 'user', 'pass', 'mydb');
$mysqli->query("INSERT INTO users (username, password) VALUES ('$username', '$password')");

// Storing API key in plaintext
file_put_contents('/var/www/config.php', "<?php \$api_key = '$api_key'; ?>");

// Transmitting over unencrypted HTTP
$ch = curl_init('http://example.com/api');
curl_setopt($ch, CURLOPT_POSTFIELDS, "key=$api_key");
curl_exec($ch);
?>

Why it's vulnerable:
Passwords and API keys are stored as plaintext in the database and filesystem, and transmitted over unencrypted HTTP.

Fixed pattern
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$api_key = $_POST['api_key'];

$mysqli = new mysqli('localhost', 'user', 'pass', 'mydb');

// Hash the password using a standard algorithm
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
$mysqli->query("INSERT INTO users (username, password) VALUES (?, ?)",
               [$username, $hashed_password]);

// Encrypt sensitive data before storage
$encryption_key = getenv('ENCRYPTION_KEY'); // Load from environment, not hardcoded
$encrypted_key = openssl_encrypt($api_key, 'AES-256-CBC', $encryption_key, 0, $iv);
file_put_contents('/var/www/config.php', 
                  "<?php \$encrypted_key = '" . bin2hex($encrypted_key) . "'; ?>");

// Transmit over HTTPS (not HTTP) and use secure headers
$ch = curl_init('https://example.com/api');
curl_setopt($ch, CURLOPT_POSTFIELDS, "key=" . urlencode($encrypted_key));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_exec($ch);
?>

05Prevention Checklist

Identify sensitive data:
Catalog all data your application handles that requires protection (passwords, tokens, PII, payment info, health records).
Use HTTPS/TLS for all transmission:
Enforce HTTPS site-wide, use secure WebSocket (WSS), and encrypt all API calls and inter-service communication.
Hash passwords, don't encrypt them:
Use bcrypt, scrypt, or Argon2 for password storage; never store plaintext or reversibly encrypted passwords.
Encrypt sensitive data at rest:
Use AES-256 or equivalent for database fields and file storage; store encryption keys separately in a key management service (KMS), not in code or configuration files.
Rotate encryption keys regularly:
Implement key rotation policies and test key recovery procedures.
Minimize sensitive data retention:
Delete or anonymize sensitive data as soon as it's no longer needed; avoid logging passwords, tokens, or PII.

06Signs You May Already Be Affected

Review your application logs and database backups for plaintext passwords, API keys, or personal information. Check your network traffic (using tools like packet capture) to confirm all sensitive transmissions use HTTPS. Audit your codebase for hardcoded credentials or encryption keys, and verify that sensitive configuration files are not world-readable or stored in version control.

07Related Recent Vulnerabilities