Mobile Application Security Testing: iOS and Android
Most security teams think about web apps. Their scanners, their checklists, their threat models — all web-first. Meanwhile, the mobile app ships to millions of devices, carries session tokens, stores sensitive data locally, and talks to the same backend APIs with almost no one watching.
This guide covers the OWASP Mobile Security Testing Guide (MSTG) methodology, the top vulnerability classes on iOS and Android, and how the mobile attack surface connects back to the web APIs you scan.
The OWASP MSTG and Mobile Top 10
The OWASP Mobile Application Security Verification Standard (MASVS) defines three security levels, and the MSTG is its companion test guide. The OWASP Mobile Top 10 maps the most critical vulnerability classes:
| ID | Vulnerability | Short description |
|---|---|---|
| M1 | Improper Credential Usage | Hardcoded credentials, insecure auth flows, broken biometric auth |
| M2 | Inadequate Supply Chain Security | Malicious SDKs, compromised build pipelines, vulnerable third-party libraries |
| M3 | Insecure Authentication/Authorization | Missing server-side auth, client-side auth decisions, privilege escalation via API |
| M4 | Insufficient Input/Output Validation | SQL injection, XSS via WebViews, command injection in deep links |
| M5 | Insecure Communication | Missing certificate pinning, accepting invalid TLS certs, cleartext protocols |
| M6 | Inadequate Privacy Controls | Excessive data collection, insecure data sharing with third parties |
| M7 | Insufficient Binary Protections | No obfuscation, easy reverse engineering, missing root/jailbreak detection |
| M8 | Security Misconfiguration | Exposed debug endpoints, verbose error messages, insecure default settings |
| M9 | Insecure Data Storage | Plaintext secrets in SharedPreferences/NSUserDefaults/SQLite, world-readable files |
| M10 | Insufficient Cryptography | Broken algorithms (MD5, DES), hardcoded keys, ECB mode, weak key derivation |
The Mobile Attack Surface
Mobile security testing splits across two primary surfaces: the client application running on the device, and the backend APIs it talks to. These require different testing techniques and tools, but findings in one area often lead to findings in the other.
Client-side surface
- Binary analysis — reverse engineering the app to extract hardcoded secrets, API keys, logic flaws
- Local data storage — SharedPreferences, NSUserDefaults, SQLite databases, Keychain/Keystore, temporary files, logs
- Inter-process communication — intent hijacking (Android), URL scheme abuse (iOS/Android), content provider access
- WebView security — JavaScript bridges, deeplink handling, insecure content loading
- Cryptographic implementation — key storage, algorithm selection, random number generation
Network and API surface
- Certificate validation — whether the app accepts arbitrary TLS certificates
- Certificate pinning — whether pinning is implemented and how it can be bypassed
- API authentication — token handling, refresh flows, session expiration
- API authorization — IDOR, privilege escalation, horizontal access control
- Sensitive data in transit — tokens in URLs, cleartext credentials, analytics payloads
Android Security Testing
Extracting and decompiling the APK
Start by getting the APK. From a connected device:
# List installed packages
adb shell pm list packages | grep -i targetapp
# Get the APK path
adb shell pm path com.example.targetapp
# Pull the APK
adb pull /data/app/com.example.targetapp-1/base.apk target.apk
Decompile with jadx for Java/Kotlin source reconstruction:
jadx -d output/ target.apk
Or use apktool to decompile smali and resources:
apktool d target.apk -o output/
Static analysis targets
After decompilation, search for common issues:
# Hardcoded secrets and API keys
grep -r "api_key\|api_secret\|password\|SECRET\|TOKEN" output/ --include="*.java"
# Insecure SharedPreferences (MODE_WORLD_READABLE)
grep -r "MODE_WORLD_READABLE\|MODE_WORLD_WRITEABLE" output/
# Cleartext network traffic allowed
grep -r "cleartext\|usesCleartextTraffic" output/
# Exported components (potential attack surface)
grep -r "android:exported=\"true\"" output/AndroidManifest.xml
# SQLite queries susceptible to injection
grep -r "rawQuery\|execSQL" output/ --include="*.java"
AndroidManifest.xml audit
The manifest defines the app's attack surface. Key things to check:
- Exported activities, services, receivers, providers — exported components can be called by other apps. Check each one for abuse potential.
- android:allowBackup="true" — allows
adb backupto extract the app's data directory without root. - android:debuggable="true" — should never appear in production. Enables full debugging access.
- Custom permissions — check permission levels (normal vs. dangerous vs. signature).
- Intent filters with sensitive data — deep link handlers that accept external URLs.
Dynamic analysis with Frida
Frida is the standard tool for runtime instrumentation — hooking into running app functions, bypassing certificate pinning, and extracting runtime secrets.
# Start Frida server on device (requires root or emulator)
adb push frida-server /data/local/tmp/
adb shell "chmod 755 /data/local/tmp/frida-server"
adb shell "/data/local/tmp/frida-server &"
# List running processes
frida-ps -U
# Attach to target and run a script
frida -U -l bypass-pinning.js com.example.targetapp
A common certificate pinning bypass script:
// OkHttp3 pinning bypass
Java.perform(function() {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {
console.log('Certificate pinning bypassed: ' + arguments[0]);
};
});
Data storage testing
# Pull app data directory (requires root)
adb shell "run-as com.example.targetapp ls /data/data/com.example.targetapp/"
# Check SharedPreferences (often cleartext XML)
adb shell "run-as com.example.targetapp cat /data/data/com.example.targetapp/shared_prefs/prefs.xml"
# Check SQLite databases
adb shell "run-as com.example.targetapp ls /data/data/com.example.targetapp/databases/"
adb pull /data/data/com.example.targetapp/databases/app.db
sqlite3 app.db .dump
iOS Security Testing
Environment setup
iOS testing requires either a jailbroken device or a device with a valid developer certificate running a re-signed app. Common tools:
- Objection — runtime mobile exploration built on Frida, handles most common iOS testing tasks
- Frida — runtime instrumentation (same as Android)
- Clutch / frida-ios-dump — decrypting App Store binaries for analysis
- class-dump / dsdump — extracting Objective-C class headers from binaries
- Hopper / Ghidra / Binary Ninja — static binary analysis
Keychain analysis
The iOS Keychain stores credentials, tokens, and certificates. Accessibility attributes determine when items can be read:
| Accessibility | Risk |
|---|---|
kSecAttrAccessibleAlways |
Accessible even when device is locked — high risk |
kSecAttrAccessibleWhenUnlocked |
Standard — acceptable for most use cases |
kSecAttrAccessibleAfterFirstUnlock |
Accessible after first unlock until reboot — background app use case |
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly |
Best — requires device passcode, not backed up |
With Objection on a jailbroken device:
# Start objection
objection -g com.example.targetapp explore
# Dump keychain
ios keychain dump
# List NSUserDefaults
ios nsuserdefaults get all
# Check plist files in app data directory
ios plist cat /var/mobile/Containers/Data/Application/.../Library/Preferences/com.example.targetapp.plist
iOS binary protections
# Check binary protections with otool
otool -hv TargetApp.app/TargetApp | grep -E "PIE|ASLR"
# Check for stack canaries
otool -Iv TargetApp.app/TargetApp | grep -E "stack_chk"
# Check for ARC (Automatic Reference Counting)
otool -Iv TargetApp.app/TargetApp | grep -c "_objc_release"
# Check encryption (0 = not encrypted = App Store DRM stripped)
otool -l TargetApp.app/TargetApp | grep -A4 LC_ENCRYPTION_INFO
iOS URL scheme and Universal Link testing
URL schemes and Universal Links define deep link entry points into the app. Test for:
- Open redirect via deeplink — does the app accept arbitrary URLs in deeplink parameters and open them in a WebView?
- Parameter injection — do deeplink parameters flow unsanitized into WebViews or local file operations?
- Sensitive state via deeplinks — can authentication state, session tokens, or sensitive operations be triggered externally?
# Trigger a deeplink from terminal (iOS Simulator)
xcrun simctl openurl booted "myapp://profile?id=12345&redirect=https://evil.com"
Network Traffic Interception
Both iOS and Android traffic can be intercepted with a proxy. Burp Suite is the standard tool. The general approach:
- Configure Burp proxy on your workstation (typically port 8080)
- Set the device's Wi-Fi proxy to point to your workstation
- Install the Burp CA certificate on the device as a trusted CA
- Browse the app — Burp captures all HTTP/HTTPS traffic
Certificate pinning will block this. Bypass approaches:
- Frida scripts — hook the pinning library at runtime (most reliable)
- Objection —
android sslpinning disableorios sslpinning disable - apk-mitm — patches the APK to disable pinning statically (Android only)
- Repackaging — modify the app's network security config (Android) or Info.plist (iOS)
The Mobile API Attack Surface
The most impactful mobile vulnerabilities are usually in the backend APIs. Mobile apps expose API calls that the web app never makes — often because the mobile team added endpoints independently of the web team, without the same security review.
After capturing traffic with Burp, look for:
- API versioning — does
/v1/exist alongside/v2/? v1 often lacks security controls added to v2. - Mobile-only endpoints — administrative or batch operations not exposed in the web app
- IDOR via mobile parameters — mobile apps frequently pass user IDs, account IDs, or resource IDs in parameters or paths
- Authentication header differences — are mobile tokens shorter-lived or differently validated?
- Unauthenticated endpoints — endpoints assumed to be internal that the app calls without auth headers
# Export Burp request log, grep for unique API paths
# In Burp: Target > Site Map > right-click > Copy URLs in this host
# Use ffuf to enumerate mobile API paths from wordlist
ffuf -u https://api.example.com/FUZZ -w /path/to/wordlist.txt \
-H "Authorization: Bearer $TOKEN" \
-mc 200,201,204,301,302,403
Common High-Impact Findings
Hardcoded credentials and API keys
The most common critical finding in mobile apps. Developers embed API keys directly in source code or resource files, assuming the app binary is opaque. It is not. Tools like MobSF (Mobile Security Framework) scan for these automatically.
Insecure data storage
Sensitive data written to locations accessible without root or sufficient protections:
- Session tokens in
SharedPreferenceswithout encryption (Android) - Credentials in
NSUserDefaultsinstead of Keychain (iOS) - Sensitive data written to SQLite without encryption (
SQLCipheris the fix) - PII written to device logs (
Logcaton Android,NSLogon iOS) - Screenshots of sensitive screens cached by the OS task switcher
Certificate pinning not implemented
Without pinning, an attacker on the same network can MitM the app with a forged certificate. This matters most for banking, fintech, and healthcare apps. Test by routing through Burp — if traffic is visible without Frida, pinning is not implemented.
Broken biometric authentication
Biometric auth that makes the cryptographic decision client-side rather than server-side. If the app checks "did the biometric succeed?" locally and then sends a request, bypass the check with Frida and watch the server honor it.
Tools Reference
| Tool | Platform | Use case |
|---|---|---|
| MobSF | iOS + Android | Automated static + dynamic analysis, all-in-one mobile scanner |
| Frida | iOS + Android | Runtime instrumentation, pinning bypass, function hooking |
| Objection | iOS + Android | Frida-based exploration shell, storage dump, pinning bypass |
| jadx | Android | APK decompilation to Java source |
| apktool | Android | APK decompilation (smali) and repackaging |
| adb | Android | Device interaction, data pull, logcat |
| class-dump / dsdump | iOS | Extract Objective-C/Swift headers from binary |
| Burp Suite | iOS + Android | HTTP/HTTPS proxy for network traffic analysis |
| apk-mitm | Android | Patch APK to disable certificate pinning |
| Ghidra / Binary Ninja | iOS + Android | Native binary reverse engineering |
Mobile Security Testing Checklist
Static analysis
- Extract and decompile the app binary
- Search for hardcoded API keys, passwords, private keys, and URLs
- Review AndroidManifest.xml / Info.plist for dangerous configurations
- Check all exported components (Android) for unauthorized access
- Identify cryptographic algorithms — reject MD5, DES, ECB mode, static IVs
- Check third-party SDK versions against known CVEs
Dynamic analysis
- Proxy all network traffic through Burp (bypass pinning if needed)
- Dump local data storage: SharedPreferences, NSUserDefaults, SQLite, Keychain
- Check device logs for sensitive data leakage
- Test all deep links and URL scheme handlers
- Test WebViews for JavaScript injection and insecure content loading
- Test biometric authentication bypass via Frida
API testing
- Map all API endpoints the app calls
- Test for IDOR on all resource identifiers
- Test unauthenticated access to all endpoints
- Check for v1/legacy API endpoints with weaker controls
- Verify token expiration and rotation behavior
- Test for sensitive data in response bodies and error messages
Ironimo's web application scanner covers the backend API surface of your mobile apps — the endpoints that handle authentication, authorization, and data access. Run Ironimo against your mobile backend to catch IDOR, broken auth, and injection vulnerabilities before your mobile app exposes them to millions of devices.
Start free scan