Back to Cheat Sheets

πŸ’Ύ Insecure Data StorageMobile 2016

OWASP Mobile Top 10 2016 - M2

HIGH RISK

πŸ“‹ What Is It?

Insecure Data Storage is sensitive data written to the device in a form that survives the moment it was needed and can be read by someone who is not the app. Credentials, tokens, personal data, and cached responses end up in preferences, plists, SQLite databases, JSON files, logs, screenshots, and clipboard history - all readable on a rooted or jailbroken device, through a backup, or by malware with the right access.

The mobile twist is that a great deal of storage is unintentional: the OS caches screenshots when the app backgrounds, keyboards remember typed text, WebViews cache pages, and crash reporters attach state. The app never "decided" to store any of it.

M2 OWASP Rank 2016
Device Attacker Owns It
Accidental Much Of The Data

⚠️ Common Exploits

  • Plaintext Preferences/Plists: tokens and passwords in key-value stores
  • Unencrypted Databases: SQLite/Realm files copied straight off the device
  • Logs: PII, tokens, and full request bodies in logcat or the console
  • Backups: app data synced to cloud or ADB backups unencrypted
  • Screenshot Cache: the OS snapshots a screen showing balances or codes
  • Clipboard: copied passwords readable by any app
  • WebView & HTTP Cache: authenticated responses persisted to disk
  • Hardcoded Secrets: keys in strings, assets, or config files

πŸ”΄ Attack Flow

1. Obtain the device, a backup, or root/jailbreak access
↓
2. Pull the app sandbox: preferences, databases, caches, logs
↓
3. Grep for tokens, passwords, PII, and key material
↓
4. Replay a recovered token or decrypt with a recovered key
↓
5. IMPACT: Account takeover from a lost phone or a stolen backup!

❌ Vulnerable Code

// Bad: credentials in plaintext key-value storage prefs.edit() .putString("password", password) .putString("auth_token", token) .apply(); ← /data/data/pkg/shared_prefs/*.xml // Bad (iOS): sensitive values in UserDefaults β†’ readable plist UserDefaults.standard.set(token, forKey: "authToken") // Bad: unencrypted database on disk db.execSQL("INSERT INTO cards(pan, cvv) VALUES(?,?)", arrayOf(pan, cvv)) // Bad: secrets in logs and crash reports Log.d("api", "login response: " + body); ← logcat, bug reports, vendors <!-- Bad: everything backed up, key compiled into the app --> <application android:allowBackup="true" /> <string name="api_key">sk_live_51H…</string> ← strings.xml is not a vault

βœ… Secure Code

// Good: keys live in hardware-backed storage; store the minimum val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .setUserAuthenticationRequired(true) .build() val secure = EncryptedSharedPreferences.create(context, "secure", masterKey, …) secure.edit().putString("refresh_token", token).apply() // …and never store the password at all - only a short-lived token // Good (iOS): Keychain, device-only, requires unlock let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecValueData as String: tokenData, ] // Good: encrypted database with a Keystore-held key val db = SQLiteDatabase.openOrCreateDatabase(file, keyFromKeystore(), null) // Good: never log sensitive payloads; strip in release builds if (BuildConfig.DEBUG) Log.d("api", "login ok") // no bodies, no tokens <!-- Good: exclude sensitive data from backup; hide the task snapshot --> <application android:allowBackup="false" /> window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, FLAG_SECURE)

βœ“ Prevention Checklist

  • Store the least data possible, for the shortest time possible
  • Never persist passwords; keep only short-lived, revocable tokens
  • Use the Keychain/Keystore for keys, and encrypt files and databases with them
  • Pick the strictest workable accessibility/authentication class for stored keys
  • Exclude sensitive data from cloud and local backups
  • Keep secrets out of logs, crash reports, and analytics payloads
  • Set FLAG_SECURE / hide sensitive screens on backgrounding
  • Disable autocorrect caching on sensitive fields and clear the clipboard
  • Disable WebView and HTTP caching for authenticated content
  • Never ship API keys in the binary; fetch scoped, revocable credentials
  • Wipe local data on logout, on token revocation, and on tamper detection

πŸ” Detection & Tools

Inspection:

MobSF objection Frida adb backup / iMazing sqlite3

Secret Scanning:

gitleaks trufflehog apktool + grep

How to Test:

  • Use the app fully, then dump the sandbox and grep for secrets
  • Take a backup and inspect what it contains
  • Watch logcat/console during login and payment flows
  • Background the app on a sensitive screen and inspect the snapshot cache
  • Log out, then check whether local data actually disappeared

🌍 Real-World

These are documented incident classes - recurring patterns rather than single CVEs.

  • Session tokens in plaintext preferences: recovered from a backup or a resold device and replayed for full account access.
  • Unencrypted local databases: messages, health data, or card details copied off a rooted device in seconds.
  • Secrets in logs: tokens and PII written to system logs and swept up by other apps, log collectors, or crash-reporting vendors.
  • Screenshot leakage: the OS task-switcher snapshot preserves balances, one-time codes, or documents.
  • Hardcoded API keys: extracted from the binary and used to call back-end services directly, outside the app.

πŸ“Œ Quick Tips

  • DO NOT store passwords or long-lived secrets on device
  • DO NOT treat preferences or plists as secure
  • DO NOT log request bodies or tokens
  • DO encrypt with Keystore/Keychain-held keys
  • DO exclude sensitive data from backups
  • DO wipe local state on logout

πŸ“œ Compliance

Related Standards:

  • OWASP Mobile Top 10 2016 - M2
  • Maps to M9:2024 Insecure Data Storage
  • OWASP MASVS STORAGE-1, STORAGE-2
  • CWE-312 Cleartext Storage of Sensitive Information
  • CWE-532 Insertion of Sensitive Information into Log File
  • CWE-798 Use of Hard-coded Credentials