iOS Common Vulnerabilities
Overview
Despite iOS's reputation for security, apps regularly contain vulnerabilities that can be identified during security assessments. Common findings include insecure data storage in the Keychain or filesystem, weak jailbreak detection, URL scheme hijacking, and insufficient transport layer security. This file covers the most frequently found iOS-specific issues.
Insecure Data Storage
NSUserDefaults
NSUserDefaults stores data in plaintext plist files. It should never be used
for sensitive data.
# On a jailbroken device, read the NSUserDefaults plist
cat /var/mobile/Containers/Data/Application/<UUID>/Library/Preferences/com.example.app.plist
Look for tokens, credentials, session identifiers, or PII stored in the preferences file.
Keychain Weaknesses
The Keychain is the secure storage mechanism on iOS, but misconfigurations reduce its protection:
- kSecAttrAccessibleAlways — data accessible even when the device is locked (weakest protection)
- kSecAttrAccessibleAfterFirstUnlock — data accessible after first device unlock (persists across locks)
- kSecAttrAccessibleWhenUnlocked — data only accessible when device is unlocked (recommended)
- kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly — strongest, requires passcode and not backed up
# objection
# https://github.com/sensepost/objection
# Inside objection session:
# Dump Keychain entries and check their accessibility
ios keychain dump
Items with kSecAttrAccessibleAlways or kSecAttrAccessibleAfterFirstUnlock
are accessible on a jailbroken device at any time.
SQLite and Core Data
# Find databases in the app's data directory
find /var/mobile/Containers/Data/Application/<UUID>/ \
-name "*.db" -o -name "*.sqlite" -o -name "*.sqlite3" 2>/dev/null
# Inspect the database
sqlite3 /var/mobile/Containers/Data/Application/<UUID>/Documents/app.db
sqlite> .tables
sqlite> .schema users
sqlite> SELECT * FROM users;
Pasteboard Leakage
The iOS pasteboard (clipboard) is shared between apps. Sensitive data copied to the clipboard can be read by other apps.
# objection
# https://github.com/sensepost/objection
# Monitor pasteboard contents
ios pasteboard monitor
Jailbreak Detection Bypass
Many apps implement jailbreak detection to prevent running on compromised devices. Common detection methods:
File-Based Detection
The app checks for the existence of jailbreak-related files:
- /Applications/Cydia.app
- /usr/sbin/sshd
- /bin/bash
- /usr/bin/ssh
- /etc/apt
- /private/var/lib/apt/
Fork-Based Detection
On a non-jailbroken device, fork() is restricted by the sandbox. A
successful fork() indicates a jailbroken device.
URL Scheme Detection
The app calls canOpenURL: with cydia:// to check if Cydia is installed.
Bypass Approaches
# objection
# https://github.com/sensepost/objection
# One-command bypass (hooks common detection methods)
ios jailbreak disable
// bypass_jailbreak_ios.js — targeted bypass
// Find the detection method with radare2/class-dump first, then hook it
if (ObjC.available) {
var SecurityManager = ObjC.classes.SecurityManager;
Interceptor.attach(SecurityManager['- isJailbroken'].implementation, {
onLeave: function (retval) {
console.log('[+] isJailbroken bypassed, original: ' + retval);
retval.replace(0x0);
}
});
}
URL Scheme Hijacking
Custom URL Scheme Vulnerabilities
iOS does not enforce uniqueness of URL schemes. If two apps register the same scheme, the behavior is undefined — the OS may route the URL to either app.
An attacker can register a malicious app with the same URL scheme to intercept sensitive data passed via deep links (e.g., OAuth callbacks).
Testing URL Schemes
# Find URL schemes in Info.plist
grep -A5 'CFBundleURLSchemes' extracted/Payload/Target.app/Info.plist
# On a jailbroken device, trigger a URL scheme
# (open Safari and navigate to the URL)
# myapp://callback?token=secret_token
// hook_url_handler.js — monitor incoming URL scheme calls
if (ObjC.available) {
var AppDelegate = ObjC.classes.AppDelegate;
// Hook openURL handler (older API)
try {
Interceptor.attach(
AppDelegate['- application:openURL:sourceApplication:annotation:']
.implementation, {
onEnter: function (args) {
var url = ObjC.Object(args[3]).toString();
console.log('[+] openURL: ' + url);
}
});
} catch (e) {}
// Hook newer openURL handler
try {
Interceptor.attach(
AppDelegate['- application:openURL:options:'].implementation, {
onEnter: function (args) {
var url = ObjC.Object(args[3]).toString();
console.log('[+] openURL (new): ' + url);
}
});
} catch (e) {}
}
App Transport Security (ATS) Exceptions
ATS enforces HTTPS connections by default. Apps that disable ATS or add exceptions weaken transport security.
# Check for ATS exceptions in Info.plist
grep -A10 'NSAppTransportSecurity' extracted/Payload/Target.app/Info.plist
Problematic configurations:
- NSAllowsArbitraryLoads = true — disables ATS entirely
- NSExceptionAllowsInsecureHTTPLoads = true — allows HTTP for specific
domains
- NSExceptionMinimumTLSVersion = TLSv1.0 — allows weak TLS versions
Binary Protections Missing
No PIE (ASLR)
# radare2
# https://github.com/radareorg/radare2
rabin2 -I extracted/Payload/Target.app/Target | grep pic
# pic = false means no ASLR — addresses are predictable
No Stack Canaries
# radare2
# https://github.com/radareorg/radare2
rabin2 -I extracted/Payload/Target.app/Target | grep canary
# canary = false means no stack protection
Debug Symbols Present
# radare2
# https://github.com/radareorg/radare2
rabin2 -I extracted/Payload/Target.app/Target | grep stripped
# stripped = false means debug symbols are included
Debug symbols make reverse engineering significantly easier.
Snapshot Leakage
iOS takes a screenshot of the app when it enters the background (for the app switcher). Sensitive data displayed on screen is captured in this snapshot.
# On a jailbroken device, find snapshots
find /var/mobile/Containers/Data/Application/<UUID>/Library/SplashBoard/Snapshots/ \
-name "*.ktx" -o -name "*.png" 2>/dev/null
Apps should implement applicationDidEnterBackground: to obscure sensitive
content before the snapshot is taken.
Cookie and Session Management
# objection
# https://github.com/sensepost/objection
# Dump cookies
ios cookies get
Check for:
- Session cookies without the Secure flag (sent over HTTP)
- Cookies without the HttpOnly flag (accessible via JavaScript)
- Long-lived session tokens that do not expire
Keyboard Cache
The iOS keyboard caches typed text for autocomplete. Sensitive text fields should disable autocorrection.
# On a jailbroken device, check the keyboard cache
cat /var/mobile/Library/Keyboard/dynamic-text.dat
Look for passwords, credit card numbers, or other sensitive data in the keyboard cache file.