SecureBlockLog inStart a pentest
Vulnerability Repository
HighCryptography

Cleartext Storage of Sensitive Data

Sensitive data such as passwords, tokens, or PII is written to disk in plaintext, exposing it to anyone with local file system or database access.

CVSS 7.5CWE CWE-312OWASP A02:2021 — Cryptographic Failures

Description

Cleartext storage of sensitive data (CWE-312 — Cleartext Storage of Sensitive Information) occurs when an application persists security-relevant data — passwords, authentication tokens, session keys, API keys, encryption keys, personally identifiable information, or financial data — in an unencrypted form on a storage medium. This includes databases, flat files, configuration files, log files, application caches, mobile device storage (SharedPreferences, NSUserDefaults, SQLite databases, and the file system), and cloud object storage.

OWASP A02:2021 — Cryptographic Failures encompasses this class because the failure is the absence of encryption where it is required. The risk materializes whenever the storage medium is accessible to unauthorized parties: database breaches, backup file exposure, mobile device theft or forensic analysis, cloud storage misconfiguration, log file exposure, or insider threats all provide paths from storage access to data exposure.

Cleartext storage is particularly prevalent in mobile applications where convenience APIs (SharedPreferences, NSUserDefaults) are used to persist tokens and preferences — these APIs store data in plaintext XML or plist files that are trivially readable on rooted/jailbroken devices or via iTunes backup extraction.

How It Works

Mobile app SharedPreferences (Android) is one of the most common cleartext storage locations. A developer stores a session token for convenience:

// Vulnerable Android
SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
prefs.edit().putString("auth_token", authToken).apply();
prefs.edit().putString("user_password", password).apply();

The token is stored in /data/data/com.example.app/shared_prefs/app_prefs.xml as:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="auth_token">eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpY2UifQ...</string>
    <string name="user_password">correcthorsebatterystaple</string>
</map>

On a rooted device, any app with root access (or an attacker with physical access performing a full device extraction) can read this file. Backup extraction tools like iMazing (iOS) and ADB backup (Android) can access these files without root on some configurations.

Database plaintext storage of passwords is a critical variant. Even if the database is secured against external access, a SQL injection vulnerability, a database backup exposed on a misconfigured S3 bucket, or a database breach exposes all user passwords directly:

-- What a breach reveals with plaintext storage
SELECT username, password FROM users;
-- alice@example.com | correcthorsebatterystaple
-- bob@example.com   | hunter2

-- vs. bcrypt hashes (no immediate usable value)
-- alice@example.com | $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj/O/rX3xsW.

Log files are a surprisingly common vector for cleartext credential exposure. Developers log request parameters for debugging — including password fields, API keys in Authorization headers, or personal data:

# Vulnerable: logs the full request including auth headers
logger.debug(f"Request: {request.method} {request.url} Headers: {dict(request.headers)}")
# Logs: Authorization: Bearer sk_live_abc123...

iOS NSUserDefaults stores data in an unencrypted plist file accessible via iTunes backup or jailbroken device analysis.

Impact

  • Credential exposure — plaintext passwords in databases or config files are immediately usable without cracking.
  • Account takeover — tokens and session keys stored in plaintext provide direct authenticated access.
  • PII breach — unencrypted personal, financial, or health data in storage triggers regulatory notification obligations (GDPR, HIPAA, CCPA).
  • Lateral movement — database connection strings and API keys stored in plaintext enable access to additional systems.
  • Physical device compromise — mobile apps storing sensitive data in cleartext are vulnerable to forensic extraction from lost or stolen devices.
  • Log-based credential theft — credentials inadvertently logged are exposed to anyone with access to log aggregation systems (Splunk, ELK, CloudWatch).

Detection

  1. Inspect mobile app data directories — on a rooted Android device or jailbroken iOS device, examine /data/data/<package>/shared_prefs/, databases/, files/, and cache/. Search for tokens, passwords, and PII.
  2. Extract iTunes backup — use tools like iMazing, iPhone Backup Extractor, or idevicebackup2 to extract and inspect iOS app data without a jailbroken device.
  3. Search database schemas and sample data — review whether password columns contain hashed or plaintext values. Look for bcrypt ($2b$), scrypt, or Argon2 prefixes; absence indicates plaintext or weak hashing.
  4. Audit log output — review what application logs record. Search for patterns like password, token, key, secret, authorization appearing in log lines.
  5. Check configuration files — search for plaintext credentials in config.yml, appsettings.json, application.properties, .env, and similar files in the repository and on deployed servers.
  6. Verify iOS file protection — check that sensitive files are created with NSFileProtectionComplete using static analysis or a jailbroken device inspection.

Remediation

Hash passwords with a strong KDF. Never store passwords in any recoverable form. Use Argon2id, bcrypt (cost ≥ 12), or scrypt:

from argon2 import PasswordHasher
ph = PasswordHasher()
stored_hash = ph.hash(plaintext_password)  # Store this, not the password

Encrypt sensitive data before storage. For data that must be recoverable (tokens, keys, PII), use authenticated encryption (AES-256-GCM) with a key stored in a hardware security module, KMS, or the OS keychain:

// iOS — use the Keychain for sensitive values
let query: [CFString: Any] = [
    kSecClass: kSecClassGenericPassword,
    kSecAttrAccount: "auth_token",
    kSecValueData: tokenData,
    kSecAttrAccessible: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemAdd(query as CFDictionary, nil)

On Android, use the Android Keystore for encryption keys and EncryptedSharedPreferences for token storage — both tie encryption to the device hardware.

Sanitize logs. Configure log filters to redact sensitive fields before writing. Use structured logging libraries that support field-level masking.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping