Decompile a typical Android APK and within the first hour you will usually
find at least one API key, a hardcoded backend URL for a "staging"
environment nobody decommissioned, and a shared-preferences file holding a
session token in plain text. Finding them needs no jailbreak, rooted device
or dynamic instrumentation, only apktool and some patience. Nobody attacked
the app in the sense people imagine when they hear "penetration test"; they
simply read it.
That is the starting point for mobile application security testing. The client binary sits in the attacker's hand, under their full control, for as long as they want it. A web app's server-side logic is protected by the network boundary, whereas a mobile app's client-side logic is protected only by how carefully it was built. This difference is why mobile application security testing is its own discipline rather than a web test run on a smaller screen, and why leaving it until late in a project tends to surface the expensive findings.
The device is not a trusted execution environment
Web security testing treats the browser as hostile territory and puts the trust boundary at the server. Mobile testing has to go further. The app itself is under examination, along with the network calls it makes, and it persists on a device that the user fully controls. So might an attacker with physical access, a repackaged build, or malware on the same device.
This changes several things developers tend to get wrong by instinct:
- Local storage is not private just because the OS sandboxes apps.
Shared preferences on Android and
NSUserDefaults/plist files on iOS are not encrypted by default. Backups, rooted or jailbroken devices, and malicious apps abusing accessibility services or content providers can all read data an app assumed was safe. Session tokens, refresh tokens, PII and cached API responses are the usual offenders, so testing checks that anything sensitive goes into the keychain/Keystore and not into a database or a log file. - Logs are a data exfiltration channel. Verbose
Log.dorNSLogcalls left in production builds routinely contain tokens, PINs or full request bodies, and on some Android versions other apps or ADB access can read them. - The backend cannot assume the client is well-behaved. Once someone has extracted the request format, the server has no way to tell a request from "your" app apart from one crafted in Burp Suite. That point comes up again and again in the rest of this article.
Definition: client-side control. Anything enforced only in the app (hidden UI elements, disabled buttons, client-side validation) is not a security control. It is a convenience for well-behaved users. The enforcement has to exist server-side or it does not exist.
Certificate pinning and transport security are necessary, not sufficient
TLS is the baseline. The more consequential mobile-specific question is whether the app pins the certificate or public key it expects, so that a device with a user-installed or attacker-installed CA in its trust store still cannot MITM the connection. Without pinning, a proxy certificate installed during testing (or during a real attack, via a malicious profile) lets anyone intercept and modify traffic the app assumed was private.
Testing this properly goes beyond confirming that pinning exists in code. It has to be enforced consistently, and the common gaps are:
- Pinning applied to the main API client but forgotten on a secondary SDK (analytics, crash reporting, an embedded WebView) that happens to carry sensitive query parameters or tokens.
- Debug builds that disable pinning "temporarily" shipping to the store by mistake, because the flag was tied to a build variant nobody re-checked.
- WebViews configured to ignore certificate errors, a pattern that turns up more often than it should in hybrid apps built on Cordova, Capacitor or a bespoke bridge.
- No pinning at all on a second or third-party API the app talks to directly, such as a payment processor, an analytics endpoint or a partner's service. The interception path is narrower but still real.
A pinning failure does not leave traffic wide open, because TLS still blocks passive eavesdropping. What it removes is protection against an active, on-path adversary, which is exactly the situation that public Wi-Fi, compromised routers and malicious VPN profiles create.
Reverse engineering and binary hardening
Every mobile binary ships to the attacker's device. Obfuscation, string encryption, root/jailbreak detection and anti-tampering checks cannot make reverse engineering impossible against a motivated attacker who has the binary. They do raise the cost and shut out the laziest attacks, which account for a surprising share of real abuse: casual API-key harvesting, quick bypasses of UI restrictions, and copy-paste cloning of a competitor's client logic.
On the hardening side, a mobile assessment typically checks:
- Whether string and constant obfuscation (ProGuard/R8 on Android, reasonable stripping on iOS) is actually enabled in the release build, rather than configured once and forgotten.
- Whether root or jailbreak detection exists and, more importantly, what the app does when it detects one. If the app detects a rooted device and carries on as normal, the check achieves nothing.
- Whether sensitive logic (licensing checks, entitlement decisions, a discount calculation) runs client-side at all, since anything computed on the device can be patched or bypassed on the device.
- Whether debug flags, verbose crash handlers and test endpoints are compiled out of release builds or merely hidden behind a toggle.
None of this replaces server-side enforcement. It delays and discourages casual attackers without stopping a determined one. For apps that carry real business logic risk, though (loyalty balances, entitlement flags, anti-cheat, DRM-adjacent features), it is a legitimate layer and one that is often under-funded.
MASVS gives the assessment a shape, not a checklist to tick
The OWASP Mobile Application Security Verification Standard (MASVS) is the recognised reference framework for this domain, much as the OWASP Top 10 anchors conversations about web testing. It groups requirements into architecture and data storage, cryptography, authentication and session management, network communication, platform interaction, code quality, and resilience against reverse engineering and tampering. The companion Mobile Application Security Testing Guide (MASTG) supplies the concrete techniques testers use to verify each one on real iOS and Android builds.
Most of the benefit of MASVS comes from deciding, before testing starts, which verification level applies. Standard controls suit most apps; the additional resilience requirements make sense for an app protecting high-value transactions or credentials. An app handling payments or health data justifies a different bar from an internal tool used by field staff on managed devices. A credible mobile application security testing engagement scopes against that distinction explicitly instead of applying one generic checklist to every client, whatever the app does.
Most "mobile" vulnerabilities are backend vulnerabilities wearing a mobile costume
Intercept traffic from almost any mobile app with a proxy, and from that point on you are testing an API. You find the same broken object-level authorisation, the same missing function-level checks and the same over-permissive endpoints that appear in API security assessments generally. Often the mobile client simply gave the tester a valid session token and a request format they could replay outside the app.
This matters commercially as much as technically. A team that commissions
"a mobile pentest" expecting findings about the app itself is often
surprised when most of the serious issues turn out to be backend
authorisation gaps: a user ID accepted from the client instead of derived
from the token, or an admin endpoint the app's UI never renders and the
server never checks. Those findings would still exist if the mobile client
were deleted and replaced with curl scripts, because the flaw sits in the
request handler, not in the Swift or Kotlin code. A serious assessment
therefore has to include API security testing
against the backend the app talks to, alongside static and dynamic analysis
of the client binary. Testing only the app, and waving the API through
because "it's internal" or "it's not directly reachable", leaves the part
that usually matters most unexamined.
Where mobile testing genuinely diverges from web testing
It helps to be precise about what actually changes, because the overlap with web application security testing is larger than vendors on either side tend to admit. Authentication logic, session handling, the API surface and authorisation between users and roles are tested the same way whichever client calls them. The mobile-specific part is everything that depends on the device as a physical, persistent object: on-disk storage a user could extract through a backup or a rooted device, IPC exposure between apps on the same phone, pinning and the ways it fails, and a binary that is open to static analysis in a way a web app's server code never is. A test that skips the client side misses risk that lives on the device. A test that skips the backend misses most of the exploitable severity, so a complete assessment covers both.
Where this lands
A mobile assessment worth paying for looks at four things together: what the app stores on the device and how; whether transport holds up against an active attacker, beyond being encrypted; whether the binary makes casual reverse engineering meaningfully harder; and whether the backend API enforces authorisation correctly regardless of which client is calling it. That last one carries most of the real risk. If you are scoping a mobile release that handles payments, health data or credentials, or you inherited an app from a previous vendor and have never had the client and server examined together, that's a conversation worth having before the next release ships.