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…
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.