Mobile apps routinely handle your banking credentials, health data, private messages, and location history — and they’re tested far less rigorously than web applications. In most mobile pentesting engagements, we find at least one critical vulnerability within the first hour. Usually more.
TL;DR
- Mobile security testing covers two major platforms: Android (APK analysis, ADB, root) and iOS (IPA analysis, jailbreak, Objection)
- The OWASP Mobile Application Security Verification Standard (MASVS) defines what a secure mobile app looks like — use it as your checklist
- Most critical findings come from: hardcoded secrets, insecure data storage, broken authentication, missing certificate pinning, and insecure API communication
- Frida + Objection is the power combo for dynamic instrumentation on both platforms
- You don’t need a physical device for most testing — emulators and simulators cover the majority of attack surface
The Mobile Attack Surface
Mobile applications are more complex than they look. A single app might include:
- The APK/IPA itself — the package distributed to devices
- Native code (C/C++ via JNI on Android, Swift/Objective-C on iOS)
- A backend API (usually REST or GraphQL)
- WebView components (essentially an embedded browser)
- Local data storage (SQLite, SharedPreferences, Keychain, files)
- Inter-process communication (IPC, Intents, deep links)
- Third-party SDKs (analytics, ads, crash reporting — each a potential risk)
A thorough mobile pentest touches all of these. This guide walks through each layer.
The Framework: OWASP MASVS
The Mobile Application Security Verification Standard (MASVS) is the definitive checklist for mobile app security. It defines controls across categories:
| Category | Focus |
|---|---|
| MASVS-STORAGE | Sensitive data not stored insecurely on device |
| MASVS-CRYPTO | Proper cryptography usage |
| MASVS-AUTH | Authentication and session management |
| MASVS-NETWORK | Secure network communication |
| MASVS-PLATFORM | Platform security controls respected |
| MASVS-CODE | Secure coding practices |
| MASVS-RESILIENCE | Resistance to reverse engineering and tampering |
The companion guide MASTG (Mobile Application Security Testing Guide) provides specific test cases for each control. Both are free and maintained at mas.owasp.org.
Lab Setup
Android Testing Lab
Option 1: Physical device (best)
- Enable Developer Options → USB Debugging
- Root the device (Magisk is the current standard)
- Install Burp Suite CA certificate in system trust store
Option 2: Android Emulator (recommended for most testing)
# Install Android Studio + Android SDK# Create AVD (Android Virtual Device) with API level 29-33# Use a non-Google Play image (they're rootable)
# Launch emulator with writable system partitionemulator -avd Pixel_6_API_31 -writable-systemCore Android tools:
# ADB — Android Debug Bridge (essential)adb devicesadb shelladb install target.apk
# jadx — APK decompiler (GUI + CLI)jadx-gui target.apk
# apktool — decode/rebuild APK resourcesapktool d target.apk -o target_decoded/
# Frida — dynamic instrumentationpip install frida-toolsfrida-server # runs on device
# Objection — Frida wrapper for mobile pentestingpip install objectionobjection -g com.target.app exploreiOS Testing Lab
Option 1: Jailbroken device
- Checkra1n or Dopamine for modern iPhones
- Install SSH, Frida server via Cydia/Sileo
- Install Burp Suite CA via Settings → Profile
Option 2: iOS Simulator (limited)
- Runs on macOS only, doesn’t support all hardware features
- Useful for static analysis and some traffic testing
- No real certificate pinning testing without a real device
Core iOS tools:
# ipa-tools / ipatool — extract IPA from device or App Storeipatool download --bundle-id com.target.app
# class-dump / dsdump — dump Objective-C class headersclass-dump -H TargetApp.app -o headers/
# Hopper / Ghidra — reverse engineer Swift/ObjC binaries# frida-ios-dump — dump decrypted IPA from jailbroken devicefrida-ios-dump -u root -H 192.168.1.100 "Target App"
# Objection — same tool works on iOSobjection --gadget "Target App" explorePhase 1: Static Analysis
Static analysis means examining the app without running it. You’re looking for secrets, misconfigurations, and code-level vulnerabilities.
Decompile the APK (Android)
# Extract and decompileapktool d target.apk -o target_decoded/
# Convert classes.dex to jar, then decompile to Java sourced2j-dex2jar target.apk -o target.jarjadx-gui target.jar
# Or directly with jadxjadx -d target_source/ target.apkjadx produces readable Java source code from the compiled APK. It’s rarely perfect, but it’s close enough for security review.
Hunt for Hardcoded Secrets
The most common critical finding in mobile apps. Developers hardcode API keys, tokens, credentials, and private keys directly in the source.
# Grep for common patternsgrep -r "api_key\|api_secret\|password\|private_key\|secret" target_source/grep -r "AWS\|firebase\|stripe\|twilio" target_source/grep -r "http://" target_source/ # cleartext URLs
# Search in decompiled resourcesgrep -r "api" target_decoded/res/values/strings.xmlReal findings from mobile engagements:
- Firebase API keys with unrestricted write access
- AWS credentials hardcoded in a config file bundled in the APK
- Admin API tokens committed directly in Kotlin source code
- Private RSA keys embedded as string constants
Check the Manifest (Android)
The AndroidManifest.xml defines the app’s permissions, exported components, and security flags:
cat target_decoded/AndroidManifest.xmlLook for:
<!-- Backup enabled — allows adb backup to extract private data -->android:allowBackup="true"
<!-- Exported components — accessible from other apps --><activity android:exported="true" ...><receiver android:exported="true" ...><provider android:exported="true" ...>
<!-- Network cleartext allowed --><application android:usesCleartextTraffic="true">
<!-- Debuggable in production -->android:debuggable="true"Each of these is a finding. Exported components are particularly interesting — they can be invoked from other apps, potentially bypassing authentication.
Check Info.plist and Entitlements (iOS)
# Extract from IPAunzip target.ipacat Payload/Target.app/Info.plist
# Check entitlementscodesign -d --entitlements :- Payload/Target.app/TargetLook for:
NSAllowsArbitraryLoads: trueinNSAppTransportSecurity— disables TLS validation- Overly permissive entitlements (keychain sharing groups, etc.)
- URL schemes that could be hijacked
Analyze Native Libraries
Many apps include native .so (Android) or .dylib (iOS) libraries. Static analysis tools:
# Check what functions are exported from a .sonm -D libnative.so
# Disassemble in Ghidra or Ghidra with MCP# Look for: hardcoded strings, crypto operations, anti-debug checksPhase 2: Dynamic Analysis
Dynamic analysis means running the app and observing its behavior — traffic, memory, filesystem, and runtime code.
Traffic Interception
The most productive setup: route the device’s traffic through Burp Suite.
Android setup:
# Install Burp CA cert on device# Export cert from Burp → DER format# For API 29+, you need system-level trust (requires root)adb push burp.der /sdcard/adb shellsucp /sdcard/burp.der /system/etc/security/cacerts/chmod 644 /system/etc/security/cacerts/burp.der
# Set device proxy to your machine IP:8080Objection one-liner for emulator:
objection -g com.target.app explore --startup-command "android sslpinning disable"Once traffic flows through Burp, exercise all app features. Capture:
- Authentication flows (login, registration, password reset)
- Data fetch requests (API calls returning user data)
- State-changing requests (profile updates, payments, settings)
- Background requests (telemetry, analytics, push registration)
SSL Pinning Bypass
Modern apps implement certificate pinning — they check that the server’s certificate matches a hardcoded value, rejecting Burp’s intercepting certificate. This needs to be bypassed for traffic analysis.
Method 1: Objection (easiest)
objection -g com.target.app explore# After attaching:android sslpinning disableObjection hooks common pinning methods (OkHttp, TrustManager, Conscrypt) and disables them at runtime.
Method 2: Frida script (more control)
// Disable Android TrustManager validationJava.perform(function() { var TrustManager = Java.registerClass({ name: 'com.test.TrustManager', implements: [Java.use('javax.net.ssl.X509TrustManager')], methods: { checkClientTrusted: function(chain, authType) {}, checkServerTrusted: function(chain, authType) {}, getAcceptedIssuers: function() { return []; } } }); // Install custom TrustManager});Method 3: Patch the APK
If Frida/Objection doesn’t work (e.g., the app detects instrumentation):
# Decompileapktool d target.apk -o target_decoded/
# Find pinning code in smali and remove/patch it# Find the OkHttpClient builder or custom SSLContext calls
# Rebuild and signapktool b target_decoded/ -o target_patched.apkkeytool -genkey -v -keystore test.jks -alias test -keyalg RSAjarsigner -keystore test.jks target_patched.apk testzipalign 4 target_patched.apk target_final.apkadb install target_final.apkFilesystem Analysis
What does the app write to disk? Local storage often contains sensitive data that shouldn’t persist.
# Pull the app's data directory (requires root or ADB backup)adb shellrun-as com.target.app # on debuggable apps
ls /data/data/com.target.app/├── databases/ # SQLite databases├── shared_prefs/ # XML key-value store├── files/ # Arbitrary files├── cache/ # Should not contain sensitive data└── no_backup/ # Excluded from ADB backupLook for:
# SQLite databases — open with sqlite3sqlite3 /data/data/com.target.app/databases/app.db.tablesSELECT * FROM sessions;SELECT * FROM users;
# SharedPreferences — plaintext XMLcat /data/data/com.target.app/shared_prefs/prefs.xml# Common bad findings: auth tokens, user IDs, flags like "is_premium=true"
# Logcat — app logging to system logadb logcat | grep com.target.app# Watch for tokens, passwords, API responses logged in cleartextiOS equivalent:
# On jailbroken device or via Objectionobjection -g "Target App" exploreios pasteboard monitor # watch clipboardios nsuserdefaults get # read NSUserDefaultsios keychain dump # dump Keychain itemsls /var/mobile/Containers/Data/Application/<UUID>/Documents/Runtime Instrumentation with Frida
Frida lets you hook any function in the app at runtime, read arguments, modify return values, and call arbitrary functions.
// Hook a specific function — read its argumentsJava.perform(function() { var TargetClass = Java.use("com.target.app.AuthManager"); TargetClass.validateToken.implementation = function(token) { console.log("[*] validateToken called with: " + token); var result = this.validateToken(token); // call original console.log("[*] Result: " + result); return result; // or return true; to always validate };});# Run a Frida script against a running appfrida -U -n com.target.app -l hook_auth.js
# List classes matching a patternfrida -U -n com.target.app -e "Java.perform(function(){ Java.enumerateLoadedClasses({onMatch: function(n,h){ if(n.indexOf('Auth') >= 0) console.log(n); }, onComplete: function(){}}) })"Frida is how you defeat custom certificate pinning, bypass root detection, patch in-memory checks, and extract encryption keys.
Bypass Root/Jailbreak Detection
Many banking and enterprise apps detect rooted/jailbroken devices and refuse to run. Standard bypass:
# Objection — one commandandroid root disableios jailbreak disable
# Frida script approach — hook the specific detection method# First, find the class/method via static analysisCommon detection methods to hook:
RootBeer.isRooted()on AndroidSHAMobileKit.isJailbroken()on iOS- Custom checks:
File.exists("/su"),File.exists("/system/xbin/su") - Checking for Magisk Manager, Cydia, etc.
Phase 3: API and Backend Testing
The mobile app is just a client. The real attack surface is the backend API it talks to.
Once you have traffic flowing through Burp, test the API exactly like a web app:
- IDOR/BOLA: Swap user IDs in API requests
- Broken authentication: Test token expiration, logout doesn’t invalidate tokens
- Missing authorization: Call admin endpoints from a regular user account
- Input validation: Inject SQL, XSS, command injection in any string field
- Rate limiting: Rapid repeated requests to login, OTP, password reset endpoints
The most common mobile-specific API finding: the mobile app API has no rate limiting because it was assumed only the official app would call it. Add Burp Intruder and enumerate away.
Phase 4: Platform-Specific Vulnerabilities
Android: Intent and Deep Link Attacks
Android Intents are messages between app components. Exported components accept Intents from any app on the device:
# List exported activities, services, receiversadb shell dumpsys package com.target.app | grep -A3 "Activity\|Service\|Receiver"
# Launch an exported activity directly — bypasses authenticationadb shell am start -n com.target.app/.AdminActivityadb shell am start -n com.target.app/.PasswordResetActivity --es "user_id" "admin"
# Send a broadcast to an exported receiveradb shell am broadcast -a com.target.app.ACTION_RESET -n com.target.app/.ResetReceiverDeep links (myapp://action) should be validated — attackers can craft URLs that trigger sensitive actions:
myapp://transfer?to=attacker&amount=10000If the app processes this without confirmation, it’s a client-side CSRF equivalent.
Android: WebView Vulnerabilities
Apps with embedded WebViews that load attacker-controlled URLs can expose dangerous capabilities:
// Vulnerable: JavaScript enabled + Java bridge exposedwebView.getSettings().setJavaScriptEnabled(true);webView.addJavascriptInterface(new JavaBridge(), "Android");
// If attacker controls loaded URL:// <script>Android.sensitiveMethod()</script>// → executes native Java code from a web pageLook for addJavascriptInterface calls in decompiled code — they’re often the path to remote code execution.
iOS: URL Scheme Hijacking
iOS URL schemes (myapp://) can be registered by any app. Malicious apps can register the same scheme and intercept OAuth callbacks or deep links:
myapp://oauth?code=AUTHORIZATION_CODEIf a banking app sends you to a browser for OAuth and expects a redirect back via bankapp://callback, a malicious app registered for the same scheme can steal the OAuth code.
iOS: Keychain Security
The iOS Keychain stores secrets securely — but apps sometimes use it incorrectly:
# Dump keychain items via Objection on jailbroken deviceios keychain dump
# Look for:# - kSecAttrAccessibleAlways (survives device lock)# - kSecAttrAccessibleAlwaysThisDeviceOnly# These are wrong — secrets should only be accessible when device is unlockedTop 10 Mobile Findings in Real Engagements
From mobile penetration testing engagements across industries, these are the most common critical and high findings:
| Finding | Platform | Typical Impact |
|---|---|---|
| Hardcoded API keys/tokens | Both | Full backend access |
| Insecure data storage (plaintext tokens in SharedPrefs/NSUserDefaults) | Both | Token theft on device access |
| Missing SSL pinning | Both | Traffic interception, MITM |
| Broken backend authorization (IDOR/BOLA) | Both | Data theft across accounts |
| Exported Android components | Android | Authentication bypass |
| Sensitive data in logs | Both | Data leakage |
| Weak session management (tokens never expire) | Both | Persistent account access |
| WebView JavaScript bridge exposure | Android | Remote code execution |
| Insecure direct object reference in file download | Both | Unauthorized file access |
| OAuth code interception via URL scheme | iOS | Account takeover |
Building a Mobile Pentest Report
Structure findings by severity, include:
- Vulnerability name and MASVS control ID (e.g., MASVS-STORAGE-1)
- Description of what was found
- Steps to reproduce — precise, reproducible
- Impact — what an attacker can do
- Evidence — screenshots, traffic captures, Frida output
- Remediation — specific code fix or configuration change
Reference the OWASP MASTG for remediation guidance on every finding.
What You Can Do Today
If you’re a developer:
- Run
grep -r "password\|api_key\|secret" src/on your mobile codebase — remove any hardcoded credentials - Check your Android Manifest for
android:exported="true"— any exported component that doesn’t need to be external should be set tofalse - Use the platform keychain (Android Keystore, iOS Keychain) for any credentials — never SharedPreferences or NSUserDefaults
- Implement SSL pinning with a pinning library (TrustKit, OkHttp CertificatePinner) — and make it updatable without an app release
If you’re a security tester new to mobile:
- Install jadx, apktool, Frida, and Objection — that’s your full Android toolkit
- Start with static analysis —
jadx-guian APK and grep forapi_key,password,http://— you’ll find something within minutes - Practice on intentionally vulnerable apps: DIVA (Android), OWASP iGoat (iOS)
- Read the OWASP MASTG — it has step-by-step test cases for every vulnerability
If you’re a CISO or security manager:
- Mobile apps should receive the same level of security testing as web apps — if they’re not in scope, add them
- Require MASVS Level 1 compliance for all mobile apps before release
- Use automated SAST tools on mobile codebases (MobSF can scan APKs automatically in CI)
Related Posts
- API Security in 2026: JWT Attacks, OAuth Abuse, and GraphQL Exploitation — mobile apps talk to APIs; the backend attack surface is equally important
- IDOR Explained: How Attackers Access Anyone’s Data by Changing a Number — BOLA/IDOR is the #1 API finding in mobile engagements
- Web Application Penetration Testing 2026: Beyond OWASP Top 10 — web pentesting methodology; mobile API testing shares the same principles
- OSINT and Recon Methodology: A Practical Guide for Security Professionals — reconnaissance includes finding mobile app versions, leaked APKs, and backend endpoints