Weakness reference
CWE-316

Cleartext Storage of Sensitive Information in Memory

This weakness occurs when an application stores sensitive data—such as passwords, API keys, or authentication tokens—in plaintext in memory without encryption…

01Summary

This weakness occurs when an application stores sensitive data—such as passwords, API keys, or authentication tokens—in plaintext in memory without encryption or protective measures. If an attacker gains access to the process memory (through a core dump, debugger, or memory disclosure vulnerability), they can directly read this sensitive information.

02How It Happens

Most programming languages store variables in memory in their raw form by default. When you assign a password or API key to a string variable, it remains readable in memory until the variable is garbage-collected or the process terminates. An attacker with local access, or one who exploits a separate memory-disclosure vulnerability, can inspect the running process's memory and extract these values. The risk is especially high in long-lived processes (daemons, web servers) where sensitive data may persist in memory for extended periods.

03Real-World Impact

Compromised credentials stored in memory can lead to unauthorized access to user accounts, backend systems, or third-party services. An attacker who obtains an API key from memory can impersonate the application and access protected resources. In multi-tenant environments, a single memory disclosure could expose credentials for multiple customers. The impact is often silent—there may be no audit trail of the data being read from memory.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import sqlite3

def authenticate_user(username, password):
    # Password stored in plaintext in memory
    db_password = "hardcoded_secret_123"
    
    conn = sqlite3.connect(":memory:")
    cursor = conn.cursor()
    cursor.execute(
        "SELECT * FROM users WHERE username = ? AND password = ?",
        (username, password)
    )
    return cursor.fetchone()

Why it's vulnerable:
The password string is stored as a plaintext Python string object in memory. Even after the function returns, the string may remain in memory until garbage collection occurs, and can be extracted via memory inspection or core dumps.

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

def authenticate_user(username, password_input):
    # Use a secure key derivation function and encryption
    key = Fernet.generate_key()
    cipher = Fernet(key)
    
    # Hash the input password for comparison
    import hashlib
    password_hash = hashlib.pbkdf2_hmac(
        'sha256',
        password_input.encode(),
        b'salt_value',
        100000
    )
    
    conn = sqlite3.connect(":memory:")
    cursor = conn.cursor()
    cursor.execute(
        "SELECT * FROM users WHERE username = ? AND password_hash = ?",
        (username, password_hash)
    )
    
    # Explicitly clear the input from memory
    password_input = None
    return cursor.fetchone()
Vulnerable pattern
<?php
function authenticate_user($username, $password) {
    // API key stored in plaintext in memory
    $api_key = "sk_live_abc123xyz789";
    
    $mysqli = new mysqli("localhost", "user", "pass", "db");
    $stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
    $stmt->bind_param("ss", $username, $password);
    $stmt->execute();
    return $stmt->get_result()->fetch_assoc();
}
?>

Why it's vulnerable:
The API key is a plaintext string in memory. PHP variables are not automatically cleared from memory, and the string can be exposed through process inspection, core dumps, or memory-disclosure bugs in extensions.

Fixed pattern
<?php
function authenticate_user($username, $password_input) {
    // Load API key from environment, not hardcoded
    $api_key = getenv('API_KEY');
    
    // Hash the password for storage and comparison
    $password_hash = password_hash($password_input, PASSWORD_BCRYPT);
    
    $mysqli = new mysqli("localhost", "user", "pass", "db");
    $stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password_hash = ?");
    $stmt->bind_param("ss", $username, $password_hash);
    $stmt->execute();
    
    // Explicitly unset sensitive variables
    unset($password_input);
    unset($password_hash);
    
    return $stmt->get_result()->fetch_assoc();
}
?>

05Prevention Checklist

Use environment variables or secure vaults
for secrets (API keys, database passwords) instead of hardcoding them or storing them in configuration files.
Hash passwords
using a strong, slow algorithm (bcrypt, Argon2, PBKDF2) and compare hashes, never store plaintext passwords in memory.
Minimize sensitive data lifetime
in memory—load credentials only when needed and explicitly clear them (set to None in Python, unset() in PHP) immediately after use.
Disable core dumps
on production systems to prevent memory snapshots from being written to disk.
Use encrypted connections
(TLS/HTTPS) to avoid transmitting credentials in plaintext, and validate that sensitive data isn't logged or cached in plaintext.
Implement memory protection
where available (e.g., mlock on Unix systems) to prevent sensitive pages from being swapped to disk.

06Signs You May Already Be Affected

Check for hardcoded credentials in source code repositories or configuration files. Review application logs and crash dumps to see if sensitive data (passwords, tokens, keys) appears in plaintext. If your application has experienced a local privilege escalation or memory-disclosure vulnerability, assume that any credentials stored in memory at that time may have been compromised.

07Related Recent Vulnerabilities