← Back to writing
Tools & Cheatsheets

iOS Data Storage Security

Apr 05, 2025
4 min read
lawbyte

iOS applications store data in several locations — some secure by default, others frequently misused. This guide covers how to locate, extract, and assess data stored by iOS apps.

iOS App Container Structure

# App container (accessible on jailbroken device)
/var/mobile/Containers/Data/Application/<UUID>/
├── Documents/ # User data, iCloud-backed
├── Library/
│ ├── Application Support/ # App data not shown to user
│ ├── Caches/ # Ephemeral cached data
│ ├── Preferences/ # NSUserDefaults (.plist files)
│ └── Saved Application State/
├── SystemData/
└── tmp/ # Temporary files, purged on relaunch

# Find app UUID
find /var/mobile/Containers/Data/Application/ -name "*.app" 2>/dev/null
# Or use objection:
objection -g com.target.app explore
# Then: env (shows all container paths)

NSUserDefaults — Plist Files

NSUserDefaults stores key-value data in plist format — commonly misused for sensitive data:

# Location
/var/mobile/Containers/Data/Application/<UUID>/Library/Preferences/<bundleID>.plist

# Read plist file on device
plutil -p com.target.app.plist

# Convert binary plist to XML for reading
plutil -convert xml1 com.target.app.plist -o -

# Using objection
objection -g com.target.app explore
# ios nsuserdefaults get

# Common sensitive data found here:
# - Auth tokens, session tokens
# - User credentials (plain text)
# - Feature flags, subscription status
# - Device/user identifiers

Keychain Analysis

The iOS Keychain is the secure credential store. Misconfigured accessibility attributes can expose Keychain items to other apps:

# Using Keychain-Dumper (jailbroken)
# https://github.com/ptoomey3/Keychain-Dumper
./keychain_dumper

# Dump all Keychain items
./keychain_dumper -a

# Specific item types
./keychain_dumper -g # generic passwords
./keychain_dumper -i # internet passwords
./keychain_dumper -k # keys
./keychain_dumper -c # certificates

# Using Frida to dump Keychain
frida --codeshare ay-kay/keychain-dump -f com.target.app -U --no-pause

# Using objection
ios keychain dump
ios keychain dump --json keychain.json

# Keychain accessibility levels (kSecAttrAccessible*)
# kSecAttrAccessibleAlways - worst: accessible always (unencrypted at rest)
# kSecAttrAccessibleAlwaysThisDeviceOnly - bad: not backed up, but always accessible
# kSecAttrAccessibleWhenUnlocked - good: only when device unlocked
# kSecAttrAccessibleAfterFirstUnlock - acceptable: accessible after first unlock
# kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly - best: requires passcode

SQLite Databases

Many apps store data in SQLite — check for unencrypted sensitive data:

# Find SQLite databases
find /var/mobile/Containers/Data/Application/<UUID>/ -name "*.sqlite" -o -name "*.db" 2>/dev/null

# Open with sqlite3
sqlite3 /path/to/database.sqlite

# List tables
.tables

# Dump schema
.schema

# Query data
SELECT * FROM users;
SELECT * FROM sessions;
SELECT * FROM messages;

# Using objection
ios sqlite connect /path/to/database.sqlite
SELECT * FROM users;

# Look for:
# - Plaintext passwords / tokens
# - Sensitive PII (SSN, credit cards, health data)
# - Encryption indicators (if data is encrypted with SQLCipher, it won't be readable)

CoreData Analysis

CoreData is an ORM on top of SQLite:

# CoreData SQLite stores in Application Support
find /var/mobile/Containers/Data/Application/<UUID>/Library/Application\ Support/ \
-name "*.sqlite" 2>/dev/null

# CoreData files:
# *.sqlite (main store)
# *.sqlite-shm (shared memory)
# *.sqlite-wal (write-ahead log)

# Open same as regular SQLite
sqlite3 CoreData.sqlite .tables

Plist Files

# Find all plist files in app container
find /var/mobile/Containers/Data/Application/<UUID>/ -name "*.plist" 2>/dev/null

# Convert and read
plutil -convert xml1 file.plist -o -
plistutil -i file.plist # Linux

# Using Python
python3 -c "import plistlib; print(plistlib.load(open('file.plist','rb')))"

# Binary plist (bplist) — convert first
file file.plist # should say "Apple binary property list"
plutil -convert xml1 file.plist -o file.xml
cat file.xml

Cached Data

# HTTP Cache (NSURLCache)
find /var/mobile/Containers/Data/Application/<UUID>/Library/Caches/ \
-name "Cache.db" 2>/dev/null
sqlite3 Cache.db
.tables
# Tables: cfurl_cache_response, cfurl_cache_blob_data, cfurl_cache_receiver_data

# Screenshots (iOS takes screenshots on app backgrounding — background snapshots)
ls /var/mobile/Containers/Data/Application/<UUID>/Library/Caches/Snapshots/
# Check if screenshots contain sensitive data (credit card numbers, messages, etc.)

# Keyboard cache (autocorrect stores typed text)
/private/var/mobile/Library/Keyboard/
# Look for user-typed passwords in keyboard dictionary

Log Files

# App logs
find /var/mobile/Containers/Data/Application/<UUID>/ -name "*.log" 2>/dev/null

# System logs (device-wide)
# From Mac: Xcode → Devices → Download Container
# Or on device:
cat /var/log/syslog | grep -i "com.target.app"

# Crash logs — may contain sensitive data/stack traces
/var/mobile/Library/Logs/CrashReporter/

# Using objection — monitor logs in real time
ios monitor pasteboard

Pasteboard (Clipboard)

# Apps that copy sensitive data to clipboard expose it to all apps
# UIPasteboard.generalPasteboard

# Monitor clipboard via Frida
Java.perform(function() {});
// iOS Frida:
ObjC.classes.UIPasteboard.generalPasteboard().string();

# Objection
ios monitor pasteboard

# What to check:
# - Does the app allow copying passwords from password fields?
# - Is OTP / 2FA code placed on clipboard?
# - Are auth tokens copied to clipboard?

Testing with objection

# Connect to running app
objection -g com.target.app explore

# View environment paths
env

# Dump NSUserDefaults
ios nsuserdefaults get

# Dump Keychain items
ios keychain dump

# List files in app container
ls
ls -la /path/to/dir

# Download a file for offline analysis
file download /path/to/database.sqlite ./local_copy.sqlite

# Monitor HTTP traffic (disables SSL pinning)
ios sslpinning disable

# Run custom Frida script
import ./my_script.js

# Check for pasteboard usage
ios monitor pasteboard

Data Storage Assessment Checklist

NSUserDefaults:
[ ] No passwords or tokens stored in NSUserDefaults
[ ] No PII stored unencrypted in preferences plist

Keychain:
[ ] Sensitive credentials use kSecAttrAccessibleWhenUnlocked minimum
[ ] kSecAttrAccessibleAlways not used
[ ] kSecAttrSynchronizable not enabled for sensitive items (excludes from iCloud backup)

SQLite / CoreData:
[ ] No plaintext passwords in database
[ ] SQLCipher or equivalent used if database contains sensitive data
[ ] WAL file doesn't expose sensitive data after normal deletion

Files:
[ ] No sensitive data in tmp/ or Caches/ (can be cleared by OS)
[ ] Documents/ doesn't contain unencrypted sensitive files
[ ] iCloud backup exclusion applied to sensitive data (NSURLIsExcludedFromBackupKey)

Logging:
[ ] No sensitive data written to NSLog or os_log
[ ] No sensitive data in crash logs

Clipboard:
[ ] Password fields have UITextFieldSecureTextEntry (auto-blocks copy in most cases)
[ ] App clears clipboard after use if sensitive data was placed there

Screenshots:
[ ] App uses UIScreen.main.isCaptured or sets secure flag on sensitive views
[ ] Snapshot on backgrounding doesn't expose sensitive screen

Discussion

Leave a comment · All fields required · No spam

No comments yet. Be the first.