notes 2026-09-20 · 4 min read · updated 2026-09-20

Mobile Application Attack Surface: Android and iOS

Manifest and exported components, deep links and app links, WebView bridges, Keychain and Keystore, pinning and mobile API authentication.

Mobile Application Attack Surface: Android and iOS

A mobile app is a client you do not control running against an API that often assumes you do. These notes separate what the app protects from what the backend must.

Android Application Surface

Android pentesting starts in the APK and ends in the backend. Staying only in the decompiler misses half the surface. An Android app includes a manifest, activities, services, receivers, providers, native libraries, network configuration and local storage. Exported components, deep links, WebViews, insecure storage and hardcoded credentials connect back to the remote API. I extract manifest, strings, network security config and endpoints before instrumenting runtime behavior. Root detection and obfuscation increase testing cost. They do not replace backend authorization or secret protection.

1
2
apktool d app.apk -o app-decoded
jadx -d app-jadx app.apk

A URL opened by the browser may enter an Activity directly and carry parameters the application never expected from another app. Deep links use intent filters. App Links add domain verification through assetlinks.json to reduce hijacking by competing apps. Route parameters may control WebViews, redirects, object IDs and internal actions. I enumerate intent filters, autoVerify settings and hosts, then trigger links through adb using canary data. A verified domain proves host ownership. The Activity still needs to validate authorization and incoming parameters.

1
adb shell am start -a android.intent.action.VIEW -d 'https://app.example/item/42'

Android Exported Components

An Activity does not need to appear in the UI to become a public endpoint. exported=true already creates a boundary between applications. Activities, services, receivers and content providers may be exported through manifest settings or intent filters. Permission checks and caller identity need to exist when the component performs sensitive actions or exposes data. I use dumpsys and the manifest to list components, then invoke each one with adb and canary extras. An intentionally exported component may be legitimate. The finding comes from privileged behavior reachable without suitable permission or authorization.

1
adb shell dumpsys package com.example.app | sed -n '/Activity Resolver Table/,+80p'

Android WebView

A WebView puts a browser inside the application and may add Java bridges that a normal website would never have. WebView may enable JavaScript, file access, mixed content and addJavascriptInterface. Origin control becomes critical when remote content or a deep link can choose the loaded URL. I enumerate WebView settings, bridges, allowed hosts and navigation overrides, then test controlled content on a lab domain. A safe bridge needs narrow methods and robust origin trust. Disabling JavaScript when unnecessary reduces the surface significantly.

1
grep -R 'addJavascriptInterface\|setJavaScriptEnabled\|setAllowFileAccess' -n app-jadx/

A link may open Safari, another app or a sensitive internal screen. Association decides who receives the link, not what the app should allow afterward. Universal Links use associated domains and apple-app-site-association. Custom URL schemes do not provide the same domain verification. Link parameters may control navigation, OAuth callbacks, object IDs and internal actions. I extract entitlements, AASA data and URL handlers, then trigger lab links and observe routing. A correctly associated Universal Link may still have an authorization bug inside the destination view controller.

1
curl -s https://app.example/.well-known/apple-app-site-association | jq .

Mobile Local Storage

A token may be protected by Keychain and still appear in logs, backups or temporary files created by another part of the app. Android Keystore and iOS Keychain protect keys and secrets through platform APIs. Apps also use preferences, SQLite, files and caches. Backup settings, device compromise, screenshots, clipboard and logs create parallel exposure paths. I classify data by sensitivity and search for every local copy, not only the primary documented storage. Local encryption needs key management outside the same file. A hardcoded AES key inside the APK only changes the representation of the secret.

1
adb shell run-as com.example.app find . -maxdepth 3 -type f -print

Mobile Certificate Pinning and Network Trust

Pinning makes interception harder. It does not fix an API without authorization or turn a compromised device into a trusted environment. Certificate pinning compares an expected certificate or public key in addition to normal PKI validation. Android Network Security Config and custom libraries implement pinning. iOS commonly uses URLSession delegates or libraries. I confirm whether pinning exists, what material is pinned and how certificate rotation works before instrumenting a lab bypass. A local bypass proves that an attacker controlling the client can observe traffic. Any server-side flaw discovered afterward remains the primary finding.

1
grep -RnE 'CertificatePinner|network_security_config|pin-set' app-decompiled/

Mobile API Authentication

A backend cannot assume a request came from the official app just because it carries the same headers as the official app. Mobile APIs use OAuth, JWT, device identifiers, attestation and refresh tokens. Any client-sent value can be reproduced from a controlled device unless backed by proper cryptographic proof. A device ID is not an authentication factor. A hardcoded API key identifies an application, not a user. I reproduce requests outside the app, then test refresh-token rotation, device binding and revocation with two accounts. Attestation raises the cost of client abuse. Object and function authorization still need to exist on the server.

1
curl -H 'Authorization: Bearer <lab-token>' -H 'X-Device-ID: 12345' https://api.example.test/me

References

This post is licensed under CC BY 4.0 by the author.