Mobile App Penetration Testing: What Gets Tested, What It Costs
mobile app security

Mobile App Penetration Testing: What Gets Tested, What It Costs

A mobile app test is an exercise in removing trust: unpack the binary, instrument the device, then check whether the server still says no. This guide covers the three layers, the static findings that appear first, pinning and why it moves the attack rather than removing it, MASVS coverage arithmetic, what a report must contain, authorization, and what actually drives the day count.

Alex Rivera
30 min read
Topics
mobile penetration testing
OWASP MASVS
MASVS testing
iOS security
Android security

A mobile app penetration test is not a website test with a smaller screen. The web client runs on a machine the attacker only borrows; the mobile client runs on a device the attacker owns, with a debugger, a proxy and a decompiler already installed. Every secret compiled into the app is a secret the attacker has. Every check the app performs locally is a check the attacker can remove. That inversion is the whole discipline: a mobile test asks what happens when the client can no longer be trusted, and then asks whether the server still holds the line. Most of the findings that cost real money are answers to the second question, and most engagements spend their budget answering the first.

The client is attacker-controlled by definition

Start with the uncomfortable premise, because every downstream decision depends on it. An attacker who wants to understand your app does not need to break encryption to get it. An Android package is a zip file with a readable manifest; an iOS archive can be decrypted on a jailbroken device or unwrapped from a developer build. Tools that were research projects five years ago are now a menu: jadx and apktool for Android, class-dump and Hopper or Ghidra for iOS, Frida and objection for both. A determined hobbyist can unpack a store build and read its strings, endpoints, keys and feature flags before lunch.

What follows is a rule you can apply without a tester present. Any control enforced only inside the app - a hidden button, a client-side PIN gate, a feature flag read from a local file, a license check that lives in the binary, a request signed with a key shipped in the bundle - is a suggestion, not a control. It may stop casual misuse. It will not stop a person who has decided to attack you, and it will not survive the first hour of a real assessment. A mobile pentest is largely the exercise of demonstrating that difference in your own app, with evidence, before someone demonstrates it on your users.

Remote Monitoring Offers

Remote Monitoring Offers

Choose Sphnix first, then compare mSpy and Eyezy.

The corollary is what makes mobile work different from web work: on the web, the server sees a browser it did not write. On mobile, the server sees an app it did write, and teams trust it accordingly. That trust is the vulnerability class. A server that accepts a client-generated "user is admin" flag, a device identifier supplied in a header, a payment amount echoed from the app, or a "verified" boolean returned by the client has moved its authorization logic to the one place an attacker fully controls.

Three layers, three different tests - and only one of them is the app

Vendors use "mobile app testing" to mean whatever they sell. Before comparing quotes, split the object into three layers, because the effort and the findings differ enormously between them.

Layer one: the client

  • What is inside the binary: strings, embedded keys, endpoints, third-party SDK inventory, debug artifacts, obfuscation.
  • How it stores data on the device: keychain classes, keystore usage, databases, caches, logs, backups.
  • How it talks: TLS configuration, pinning, certificate validation, cleartext exceptions, custom crypto.
  • What it exposes to other apps: exported components, deep links, WebViews, pasteboard, extensions.

Layers two and three

  • The platform surface: the operating system the app runs on, and any assumption the app makes that it is intact - jailbroken iOS, rooted Android, instrumented runtime, emulator.
  • The backend: the APIs the app calls, the authorization decisions behind them, the token model, and the privacy of what the app and its SDKs transmit.
  • Most real breach paths cross all three: an identifier harvested from the client, reused against the backend, from a device the platform no longer vouches for.
  • A test that stops at layer one can be complete and still miss the finding that matters.

A genuine mobile engagement covers all three, and says so in the scope document. If a quote describes "scanning the APK", you are buying layer one, partially. If it describes "testing the app and its APIs against OWASP MASVS and the API Top 10", you are buying the thing that finds account takeover. The difference in price is usually smaller than the difference in findings.

What the numbers say about untested apps

The published benchmarks are consistent enough to be useful, and worth quoting at a planning meeting because they reframe "we do not have time for this" as a base rate. NowSecure's MASVS benchmark, run across roughly 6,500 apps, found that 95 per cent of tested apps failed at least one MASVS control. It is not a list of exotic zero-days: it is storage, transport, authentication and platform hygiene, checked against a published standard, failing almost universally.

Privacy testing tells the same story with newer numbers. In NowSecure's September 2025 analysis of 23,300 iOS app packages, 42 per cent were missing their main privacy manifest and 97 per cent were missing the required privacy manifests for their third-party SDKs. Of 50,000 apps analysed in the same period, more than 77 per cent contained personally identifiable information, and of 378,000 Android apps, 62 per cent requested at least one dangerous permission. Data at rest has been the most common mobile weakness for a decade: Positive Technologies reported insecure local storage in 76 per cent of the apps it examined in 2019, and the architecture that produced that figure has not changed - apps still cache, still log, still write to shared storage, still hand data to SDKs nobody reviewed.

Read those numbers as a prior, not a prophecy. They say a randomly chosen app probably has several cheap-to-find defects before anyone looks for anything clever. That is what a first engagement should find, and a first engagement whose report contains only one dramatic finding and no hygiene findings is a report worth questioning.

Static analysis: the binary you ship is a document

Static review is the part of the work that needs no device and produces the fastest findings. The tester unpacks the build, reads the manifest or the property list, walks the class structure, and greps for the things that should never have shipped. It is unglamorous, and it is where most confirmed findings come from, because a shipped app is a description of its own weaknesses.

On Android the review starts in the manifest and goes outward: which components are exported and reachable without permission, which intent filters any installed app can trigger, which content providers leak rows through a URI, whether backups are enabled, whether cleartext traffic is permitted, and whether the debug flag survived the release build. On iOS it starts in the property list and entitlements: App Transport Security exceptions, URL schemes registered under a name anyone else can also claim, associated domains, keychain sharing groups, background modes, and whether the release configuration still allows debugging or ships an entitlement it should not.

The static checklist that produces findings, in order of hit rate

  • Embedded secrets. API keys, signing secrets, third-party service tokens, hardcoded credentials and test accounts. The MASTG test for hardcoded secrets is one of the oldest in the guide and still one of the most productive. A key that ships is a key that has leaked, whether or not anyone has used it yet.
  • Endpoint inventory versus expectations. Every hostname, path and websocket in the bundle, compared with the API documentation. The comparison is usually where staging hosts, legacy versions, internal admin paths and abandoned partner integrations appear.
  • Exported components and deep links. Android exported activities, services, receivers and providers; MASTG-TEST-0028 covers deep links and MASTG-TEST-0029 covers sensitive functionality exposed through IPC. On iOS, custom URL schemes (MASTG-TEST-0075) that any app can register and intercept.
  • Transport exceptions. Domains exempted from App Transport Security on iOS; cleartext allowances and user-installed CA trust in the Android network security configuration. Each exception is a testing instruction written by the development team.
  • Debug artifacts. Debuggable builds, verbose logging, test flags, hidden menus, sample data, code paths compiled out but not removed - MASWE-0061, debug artifacts not removed.
  • Third-party SDK inventory. Every SDK with its version and its network destinations. This is now a supply-chain question as much as a privacy one, and it is rarely documented anywhere except inside the binary.
  • Cryptography in the client. Custom encryption, hardcoded IVs and keys, ECB mode, weak hashing, and "encryption" that is really base64 with a fixed key in the source. Client-side crypto is obfuscation at best; the finding is usually that the design assumed otherwise.

The output of static review should be a table, not a narrative: file or component, what was found, why it matters, how an attacker reaches it, and the MASTG test that produced it. If the report has prose and no table, ask for the table. It is the artefact you will need when the fix is prioritised against everything else engineering wants to do this quarter.

Dynamic analysis: the app on a device you do not control

Dynamic work is where the tester behaves like the attacker on a device that has already been compromised, because that is the honest model for a lost or stolen phone and for a user who is themselves the adversary. On Android that means a rooted device or an emulator with a writable system partition, frida-server or objection attached, a proxy with a trusted CA, and the app running while all of it happens. On iOS it means a jailbroken device or a virtualised device, a decrypted binary, and the same instrumentation.

The mechanics are well documented and mostly boring to describe: hook the certificate validation callbacks, watch the traffic, exercise every screen, and record what lands in storage, logs and memory as you go. What makes the work valuable is not the tooling but the questions asked while the app runs.

  • What is written to disk, in which location, and with which protection class? Does a session token appear in a plain SQLite file, a preferences file or a log line?
  • What survives a backup? Android backup rules and iOS device backups both move application data off the device, and the exclusion list is often empty.
  • What is captured when the app is backgrounded? Screenshots cached for the app switcher are a classic source of leaked balances, medical records and message threads - MASTG-TEST-0010, auto-generated screenshots.
  • What does the clipboard hold, and for how long? MASTG-TEST-0073 covers the iOS pasteboard, and MASWE-0030 covers improper use of the clipboard on both platforms.
  • What happens in a hostile environment: an overlay drawn on top of the login screen, a malicious keyboard, a second app that registered the same URL scheme, a proxy that rewrites a response?
  • What does the app do when the network lies? Modified, delayed, replayed responses; a server that returns another user's object to a valid token.

Two practical constraints deserve to be written into the scope. First, test the build users have, not the one that compiles today: a store build behaves differently from a debug build, and findings from a development build are often dismissed as artefacts. Second, use real devices. Emulators are efficient for breadth, but attestation, biometrics, secure hardware, Bluetooth, NFC and some anti-tampering behaviour only tell the truth on hardware, and a report that says "not tested on device" is a report with a hole in it.

Certificate pinning: the first thing a tester bypasses, and the last thing a team should rely on

Almost every mobile engagement starts by defeating pinning, because without traffic there is no dynamic testing. That is not a criticism of pinning - it raises the cost of interception meaningfully against malware and against casual proxy users - but it should calibrate expectations. Pinning is defeated in minutes with a Frida hook on the trust manager, a repackaged build with the pin removed, or a virtualised device with the check patched out. Android's network security configuration and iOS's pinned trust evaluation are both patchable by an attacker who controls the device, because the check runs in code the attacker also controls.

So the test does two separate things, and the report should keep them apart. First it demonstrates the bypass, with the hook and the intercepted traffic as evidence. Then it asks the question that actually matters: with interception available, what does the traffic reveal and what can be replayed? A pinned app that sends a bearer token over a channel an attacker can read on a compromised device is still leaking that token. Pinning moved the attack from the network to the device; it did not remove it.

What pinning is genuinely good for is narrower than the marketing suggests, and worth stating plainly to stakeholders: it blocks passive interception on hostile networks and defeats a class of malware that proxies traffic without instrumenting the app. Layer it. Validate the certificate chain properly first, pin with a backup pin and a rotation plan, and never treat it as an authorization control. The control that survives a compromised device is on the server: short-lived tokens, refresh rotation, device binding, and a server that re-checks authorization on every request rather than trusting a session it issued last month.

Authentication and session: where mobile apps lose accounts

Account takeover on mobile rarely begins with a broken password. It begins with a token in the wrong place, or a flow that trusts something the client asserts. Five patterns recur often enough that a test should look for them explicitly.

Token handling

  • Where the access and refresh tokens live: keychain with the right accessibility class, keystore-backed encryption, or a preferences file with base64 and good intentions.
  • Whether refresh tokens rotate, whether old ones are revoked, and whether a stolen refresh token still works after the user changes their password.
  • Whether logout invalidates server-side. A logout that only clears local storage leaves a valid token in an attacker's hands.
  • Whether tokens are bound to anything - device attestation, a client certificate, a device key in secure hardware - or are bearer tokens that work from anywhere.

Flows that get hijacked

  • Custom URL scheme redirects in OAuth: another app registers the same scheme and receives the authorization code. Native apps should use PKCE with a claimed HTTPS redirect, as RFC 8252 describes.
  • Password reset and magic links: token leakage through referrers, logs, or a universal link that opens another app first.
  • Biometric gates that fall back to a device passcode, or that unlock a screen but not the key material protecting the session.
  • Deep links that set a session, a user identifier or a password reset target from parameters - MASTG-TEST-0028.
  • One-time codes with no per-account attempt limit, no expiry, and no binding to the device that requested them.

Biometrics deserve their own sentence because they are so often implemented as theatre. A fingerprint prompt that returns true and then lets the app read a token from ordinary storage protects nothing: the attacker with the device does not need the fingerprint, they need the token, and the token was never gated by the biometric result. The implementation that actually binds a secret to biometrics uses the platform's key protection path - SecAccessControl with biometry on iOS, a keystore key requiring user authentication on Android - so the key material itself is unusable without a successful match, and unusable on another device.

The same logic applies to device binding. A token bound to a device identity that the server can verify through platform attestation is worth more than a token bound to nothing. Both platforms now offer that primitive: Play Integrity verdicts on Android, App Attest and DeviceCheck on iOS. Neither is a silver bullet, both need a server-side policy about what to do when verification fails, and both are worth testing precisely because so many implementations check the verdict and then ignore it.

The platform surface: exports, deep links, WebViews and intents

This is the part of mobile testing with no real web analogue, and it is where a test written against a generic checklist quietly stops. An app is not a sandboxed web page: it is a set of components the operating system can start on behalf of other apps. Whether those components check who is calling is a question only the app's own code answers.

On Android, every exported activity, service, broadcast receiver and content provider is an entry point, and so is every intent filter with a browsable scheme. The tests that matter: can another app start a privileged activity directly and skip the login screen; can it query a content provider and read rows it should not; can it supply a PendingIntent (MASTG-TEST-0030) that the vulnerable app fills in with its own identity; can it trick the app into loading attacker-controlled content through an implicit intent (MASTG-TEST-0026) or a WebView (MASTG-TEST-0031, MASTG-TEST-0033). Task hijacking and overlay attacks (MASTG-TEST-0035) belong here too, and both are cheap to test with two devices and a harmless sample.

On iOS the equivalents wear different names: custom URL schemes anyone can register (MASTG-TEST-0075), universal links that depend on a correctly hosted association file (MASTG-TEST-0070), app extensions that share a keychain group (MASTG-TEST-0072), share extensions that receive documents and text (MASTG-TEST-0071), and WebViews that load remote content with a message handler attached (MASTG-TEST-0076, MASTG-TEST-0077). The failure mode is consistent across both platforms: a component written for the app's own convenience, exposed to the whole device, with no check on the caller.

WebView bridges merit a specific warning because they are the most common way a mobile app turns a browser bug into a mobile vulnerability. A JavaScript interface exposed to a WebView that can be navigated to attacker-controlled content is remote code execution in the app's own process. If the bridge is needed, restrict navigation to a fixed allowlist, never expose reflection or file access, and verify the origin on the server rather than in JavaScript.

Data at rest is a device problem, not a server problem

The server can encrypt a field; only the client decides where the decrypted value lands. That is why storage testing is a category of its own, and why the fixes are unglamorous and cheap. The review enumerates every place data lands on the device, then asks which protection class covers it.

  • iOS keychain accessibility classes. The default is not the strongest. Items that should not migrate to a restored device need ThisDeviceOnly; items that should not exist while the device is locked need WhenUnlockedThisDeviceOnly rather than Always. Biometric-protected items need the right SecAccessControl flags, including whether a passcode fallback is permitted.
  • Android storage. Internal storage is private to the app and readable on a rooted device; keystore-backed encryption with hardware backing, StrongBox where available, is the correct home for keys rather than for bulk data. Shared preferences and unencrypted SQLite databases are the two most common findings in this category.
  • Backups and cloud sync. Android backup rules and iOS iCloud backups move app data off the device. If a token belongs only on the phone, that has to be stated in configuration rather than assumed.
  • Caches and SDKs. Image caches, HTTP caches, crash reporters, analytics queues and A/B testing SDKs all write to disk. A sensitive screen cached as a JPEG is a leak that no amount of TLS prevents.
  • Logs and crash reports. Verbose logging in release builds, analytics events carrying identifiers, and crash reports that include request bodies. The report should show the actual log line containing the actual token.
  • The app switcher and the clipboard. Screenshots taken by the operating system when an app is backgrounded, and content left on the pasteboard, are readable by other apps on the device in more circumstances than most teams assume.

An easy way to frame this for engineering: for each sensitive datum, name the device location, the protection class and the lifetime. Three columns, one row per datum, and the gaps become obvious without anyone needing to read a standard.

Resilience is friction, not a security boundary

Root and jailbreak detection, anti-debugging, integrity checks and obfuscation live in their own MASVS group for a reason. The standard's resilience profile, MAS-R, assumes the user of the device is the adversary, and it says plainly that these measures raise effort and cannot eliminate the attack. That framing matters commercially as well as technically: resilience buys time, deters automated repackaging, and produces fraud signals, but it does not protect data, because the data is on the device the attacker controls.

Good resilience work is measurable and it is honest about its limits. Detection of a rooted or jailbroken device, of an emulator, of an instrumented runtime, of a debugger attached at the moment a payment is authorised - MASVS-RESILIENCE covers each of these, and MASWE-0051 through MASWE-0064 map the individual weaknesses. Attestation belongs here too: Play Integrity and App Attest give the server a verifiable statement about the app and the device, and a server that acts on a failed verdict is doing something real, while a client that merely shows an error message is not.

The test for this group is adversarial by design: bypass the root check, dump the memory, attach the debugger, repackage the app and see what still works. A report that lists four bypasses and no business impact is a resilience review. A report that shows a bypassed root check followed by a lifted rate limit on the login endpoint is a finding, because the control that failed was assumed to protect money.

The backend is where the test earns its money

If you commission one thing, commission this. The client-side work is necessary, but the findings that lead to lost accounts and lost revenue sit in the agreement between the app and the server: an endpoint that trusts a client-supplied identifier, a token that never expires, an authorization check that runs on the client, a rate limit that exists only in the app's UI.

Mobile backend testing is API testing with a specific threat model, and the technique is the same one our API security testing guide sets out in detail: two valid identities at the same privilege level, an object identifier belonging to each, and a request that swaps one for the other. Read returns another user's record, write modifies it, delete removes it, a nested path reaches a child object through a parent that was authorised, and a collection endpoint returns rows nobody asked for. Then repeat with a token from the mobile app rather than the web session, because mobile APIs frequently expose older versions, debug endpoints and partner routes that the browser never sees.

Three mobile-specific variants are worth naming. First, the endpoint that accepts a device identifier, an install identifier or a "platform" header as an authorization input - those values come from the client and are attacker-chosen. Second, the endpoint that accepts a request signature computed with a key embedded in the app, which is a shared secret with everyone who downloaded it. Third, the endpoint that trusts a boolean: is_verified, is_premium, is_admin, returned by the client and written to the session. Each of these is a five-minute test and a permanent fix.

Where a full API assessment is out of scope, say so explicitly rather than assuming the app test covered it. A mobile test that exercises the twenty endpoints the app calls is not a substitute for an API assessment across the whole surface, and the report should state the difference in coverage rather than leave the reader to guess.

Scope that survives contact with reality

Most disappointing engagements are disappointing for scope reasons, not skill reasons. The scope document should name, before anyone tests anything: the app and its version or build number, the platforms and minimum OS versions, the backend hosts and environments in scope, the accounts and roles provided, the test data and whether it is seeded, the devices used, the testing window, the permitted techniques and the prohibited ones, and the person who can authorise a scope change mid-test.

Two scope decisions deserve a conversation. Whether production is in scope: testing against production with real customer data is a legal and privacy problem disguised as a convenience, and a staging environment with production-like data is usually the better trade. And which builds: a release build from the store, an internal build, or both. The honest answer is that the store build is the one that matters, and a test that only saw the internal build should say so in the first paragraph of the report.

Coverage arithmetic: turning MASVS-L2 into a number

"We tested against MASVS-L2" is a claim, not a coverage figure. The standard defines eight verification groups - storage, cryptography, authentication, network communication, platform interaction, code quality and build settings, resilience, and privacy - and a quote that does not say which groups were tested, on which platforms, at which profile, is a quote you cannot compare with another one.

Do the arithmetic in the scope conversation. Eight groups, two platforms, one build per platform, and each group resolves into test cases drawn from the MASTG. Take authentication as an example: it is not one test, it is a set that includes login flows, biometric binding, session lifetime, token revocation, password policy enforcement on the server, and per-account rate limiting. Multiply that by roles, because a marketplace app with buyer, seller and support roles has three authentication surfaces, not one, and the tests that matter are the ones that cross a role boundary.

A defensible coverage statement looks like this

  • Groups tested, with the profile applied to each - for example MAS-L1 for storage, network and platform interaction; MAS-L2 for authentication; MAS-R for resilience.
  • Platforms and OS versions, the app build identifiers, and whether the store build or an internal build was used.
  • Number of test cases executed, with the count of passed, failed and not-applicable, per group and per platform. A single total is not enough, because a hundred passes in storage do not offset a skipped authentication group.
  • Explicit exclusions with a reason: features not reachable in the test environment, third-party components that could not be assessed, platform features unavailable on the test devices, endpoints outside the agreed API scope.
  • Backend coverage, stated separately: how many endpoints, how many roles, and whether authorization was tested across tenants or only within one.

Two numbers in that list are the ones to insist on: the not-applicable count and the exclusions. Every engagement has them, and a report with zero of both is a report that either tested everything or is not telling you what it skipped. The first is implausible; the second is common.

What the report has to contain

A finding is not a sentence. It is a reproducible artefact that survives being handed to an engineer who was not in the room and to a manager who has to decide whether to delay a release. Every finding needs the same six parts, and a report missing any of them will be argued about instead of fixed.

  • A title that names the defect and the impact, not the tool. "Session token readable in shared preferences on rooted devices" is a finding. "Insecure storage" is a category.
  • The mapping: MASVS group, the MASWE weakness where one applies, the MASTG test that produced it, and the platform. This is what makes the report comparable across engagements and auditable by someone else.
  • Severity with a rationale: CVSS vector plus the business consequence, kept apart. A CVSS 6.5 that exposes every customer's address is a different decision from a CVSS 6.5 that exposes a debug menu.
  • Reproduction: device model, OS build, app version and build hash, test account role, preconditions, numbered steps, and the commands or hooks used. If the tester used an instrumented runtime, say which and how, because the fix team will need to reproduce it.
  • Evidence: the intercepted request, the log line, the file path and permissions, a screenshot or a screen recording. Evidence is what stops a finding being closed as "cannot reproduce" three weeks later.
  • Remediation at class level, and a retest criterion: what to change in the design, not just the line, plus the specific observation that will prove it fixed. "Add encryption" is not a remediation; "move the token to the keychain with WhenUnlockedThisDeviceOnly and invalidate the old token server-side" is.

Ask for the report in writing before the engagement starts, including the format of the finding template and whether the raw evidence is included. Vendors that charge separately for evidence, or that deliver only a PDF with no test IDs, have told you something about how the work was done.

Retest: the part that decides whether you were sold a document or a fix

A first test without a retest is an expensive opinion. The retest is where the value is realised, and it should be priced and scoped at the start rather than negotiated after the findings land. A sensible retest covers every high and critical finding, a sample of the mediums, and a check that the fixes did not open anything new - a regression pass over the same test cases that previously passed, not just the ones that failed.

Two habits make retests cheap. First, ask for fixes to be mapped to findings in the tracker, with the build that contains each fix, so the retest can be run against a known state. Second, insist that a finding is closed only when the retest observes the fixed behaviour, not when a commit exists. The distinction is not pedantic: token storage fixes routinely ship the keychain change but forget to invalidate the tokens already issued, and the retest is the only step that catches it.

For teams with an internal security function, the retest is also the moment to convert the finding into a permanent regression test - a CI check for hardcoded secrets, a lint rule that fails an exported component without a permission, a pre-release step that refuses a debuggable store build. Findings recur because the process that allowed them did not change; the retest is the cheapest opportunity to change it.

Effort and cost: what actually drives the number

Mobile testing prices are quoted in tester-days, and the day count is driven by five variables that you control. Understanding them makes quotes comparable and stops the conversation from becoming a negotiation about an hourly rate.

  • Platforms. Two platforms are not twice one platform: shared backend, shared business logic and shared findings reduce the marginal work, but the platform-specific surface - exports, keychain, attestation, biometrics - is genuinely separate. Budget roughly one and a half times the single-platform effort for both, not double.
  • Profile. A MAS-L1 static and dynamic pass on a staging build is a few days per platform. Adding MAS-L2 authentication work and a MAS-R resilience pass on top is where the days go, because each requires instrumented devices, bypasses and careful evidence.
  • Roles and feature breadth. The number of distinct user roles, not the number of screens, predicts the authentication effort. Three roles with different permissions and a support role that can act on behalf of users is a bigger job than a hundred screens with one role.
  • Backend depth. Whether API authorization is in scope, and how many endpoints and tenants it covers, is often the largest single line item - and the one most often left out to hit a budget, then discovered later as a gap.
  • Third parties. Apps with a long SDK list, payments, or a hardware integration need more setup and more documenting. A Bluetooth lock integration can consume a day before the first test case runs.

Two cost questions worth asking explicitly. Is the retest included, or priced separately? And is reporting time included in the day count, or does a five-day test produce a one-day report that nobody billed for? Both are legitimate ways to structure an engagement, and both cause friction when they are discovered after the fact. Day rates vary by region and by seniority; ask for the day rate and the day count separately so you can compare two offers on the same basis.

Authorization: the document that makes the test lawful

Every technique in this article is an attack when it is aimed at a system you do not own. The difference is paperwork, and it needs to be real paperwork - signed, specific, and retained. A written authorization for mobile testing should name the application by package name or bundle identifier and version, the backend hosts and environments in scope, the accounts and roles provided, the testing window with dates and hours, the techniques permitted, the techniques excluded, how test data will be handled and destroyed, who is authorised to approve a scope change, and an emergency contact who can be reached during the test if something behaves unexpectedly.

Three points are where engagements go wrong. The first is ownership: if you hired an agency to build the app, the app may be yours but the backend may be theirs, and testing the backend without their permission is not covered by your ownership of the app. Get the authorization from whoever controls each system. The second is third-party apps: no authorization you can sign permits testing someone else's application, and app store terms do not change that. The third is real user data: if the only environment available has live customer records, say no and test staging, because the privacy exposure created by the test is itself a reportable incident in most jurisdictions, and the obligation sits with you rather than with the tester.

The legal frame varies by country but the shape is the same. In the United States, the Computer Fraud and Abuse Act and state equivalents turn unauthorised access into a criminal matter, and the authorisation letter is the defence. In the United Kingdom, the Computer Misuse Act applies, and contractual authorisation plus documented scope is what separates a test from an offence. Across the EU, the same conduct is covered by national implementations of the directive on attacks against information systems, alongside the GDPR obligations that apply to any personal data the test touches. Where a tester finds something genuinely dangerous, the norms are also well established: coordinated disclosure, a private channel, a reasonable window before publication, and no pressure to publish for marketing.

If you are buying mobile testing on a marketplace, read the guide to spotting hacker-for-hire scams before you pay a deposit. The failure mode is not usually a bad tester; it is a broker with no tester at all, reselling a template report.

Compliance: where a mobile test now has to feed

Mobile testing used to be an engineering exercise with an optional compliance appendix. That changed. The EU Cyber Resilience Act entered into force in December 2024, its vulnerability reporting obligations apply from 11 September 2026, and its main obligations apply from 11 December 2027 to products with digital elements placed on the EU market - which includes apps sold or distributed there, and the software components inside them. Manufacturers must design to essential cybersecurity requirements, document them, ship security updates for the support period they declare, and report actively exploited vulnerabilities and severe incidents within the prescribed deadlines: an early warning within 24 hours, a fuller notification within 72 hours, and a final report afterwards.

The practical consequence for a mobile team is that a penetration test is no longer only a release gate. Its findings become risk-management evidence, its retest becomes proof that vulnerabilities were remediated, and its scope statement becomes part of the technical documentation. Keep the reports, keep the retest evidence, and keep the version identifiers - an auditor will want to know which build was tested and which build fixed it.

Other regimes map onto the same evidence. PCI DSS for mobile payments expects penetration testing of the payment surface and remediation evidence on a recurring cycle. HIPAA expects risk analysis and risk management for apps handling health data, and a test that documents storage and transmission findings feeds both. GDPR Article 32 expects technical measures proportionate to risk, and the privacy group in MASVS produces exactly the artefact that argument needs: what the app and its SDKs collect, where it goes, and whether the store privacy declarations match the behaviour.

How to tell a mobile tester from a reseller

The mobile security market contains excellent small firms, large consultancies, and a layer of brokers who own a website and a payment processor. The work is not hard to distinguish if you know what to ask for. A real mobile tester asks for the build and the test accounts before quoting a final number, because the effort depends on what is in the binary. A reseller quotes a price from a web form.

  • Ask which profile they will apply to which MASVS group, and ask them to name three MASTG tests they expect to run on your app. Vague answers are a warning; the specific answers tell you whether they have read the standard recently.
  • Ask what devices they use. "Emulators and a virtual device service" is a legitimate answer for some work and an incomplete one for biometrics, attestation or secure hardware. A tester who can explain that trade-off is a tester.
  • Ask to see a redacted report from a previous mobile engagement. You are looking for the six-part structure above, test IDs, and evidence that a real device was used - not a sample PDF with lorem ipsum.
  • Ask who does the work and whether it can be subcontracted. If the answer is a marketplace, you are buying a broker, and the scope, the evidence and the retest all become guesses.
  • Ask what happens if nothing is found. A tester who says "then the report says what we covered and what the residual risk is" is telling the truth; anyone who promises findings, or promises a clean bill of health before looking, is selling something else.

The same test applies to fixed-price packages. A package that covers one platform, no backend and a retest only on request is not a mobile app penetration test, whatever the page calls it. Compare offers on groups, platforms, backend depth and retest inclusion, and the cheapest offer usually stops looking cheap.

Between engagements: what your team can do itself

An annual test is a snapshot; the vulnerabilities arrive with each release. The useful complement is a small set of checks that run continuously and cost almost nothing.

  • Scan every build for secrets before it reaches a store. A pre-commit hook and a CI step catch the most common mobile finding before it ships.
  • Fail the build if the release variant is debuggable, if logging is verbose, or if a staging host appears in a release configuration.
  • Maintain an SDK inventory with versions and owners, and review the privacy declarations each SDK requires. This is now an app store requirement on both platforms, and it is also how supply-chain surprises are caught early.
  • Run a static analyser on the mobile codebase and triage what it reports for exports, WebView configuration and cryptography. Automated tools find the patterns; they cannot judge impact, so triage rather than trust.
  • Keep the storage map current - one row per sensitive datum, with location, protection class and lifetime - and check it when a new feature stores something new.
  • Re-run the internal checklist against each major release, and bring the external tester in when the attack surface changes: new authentication, new payment flow, new platform, new third party.

None of that replaces an independent test, and none of it needs a budget line. What it does is stop the same class of finding from reappearing every year, which is the most common way mobile security budgets get wasted.

If you need this done properly

Our penetration testing service covers mobile applications on Android and iOS against MASVS, including the backend APIs the app depends on, with a written authorization, a build-specific scope and a retest that closes each finding against evidence. If you are shipping a mobile app and have never had it tested, or your last test produced a PDF with no test IDs, send us the scope - the app, the platforms, the backend and the timeline - and we will tell you what the work involves before you commit to it. For the API layer that usually carries the real risk, the API security testing guide explains the method we use; for the wider engagement, see how a penetration test is scoped and run.

Sphnix Monitoring Dashboard

Track messages, location, social media and activity signals with an authorized monitoring dashboard.

Try Sphnix Now →

Need Professional Help?

Hire verified ethical hackers for authorized recovery, security testing and incident support.

Hire a Hacker →

Professional Services

Explore cybersecurity services for audits, recovery, forensics and defensive hardening.

View Services →

Questions? Our experts are ready to help.

Contact Us for Free Consultation →

Frequently Asked Questions

Effort, not calendar time, is the honest answer. A single-platform static and dynamic pass at MAS-L1 against a staging build is typically four to seven tester-days. Both platforms with authentication work at MAS-L2 and a resilience pass at MAS-R usually lands between ten and eighteen days, and a backend API assessment across several roles adds more. Retest adds one to three days depending on how many findings were fixed. If a deadline is the constraint, shrink the scope in writing rather than the effort - a test that skipped the authentication group still produces a report, it just cannot support the claim that the app was tested.

Yes for the part of the work that assumes a compromised device, which is the honest threat model for a lost phone or a user who is themselves the adversary. Attaching a debugger, reading application storage directly and bypassing pinning all require elevated access to the operating system. That is not a reason to skip it: it is the only configuration in which you can prove what an attacker holding the device can extract. Testing on a stock device answers a different and narrower question - what a hostile app can reach through the platform surface - and is worth doing as well, not instead.

No, and the gap is not marginal. Automated mobile analysers are good at hardcoded strings, manifest misconfiguration, weak TLS settings and bundled library versions, and they are worth running on every build for exactly those. They do not log in, they do not hold a valid session, they do not swap object identifiers between two real accounts, and they cannot tell you whether an authorization decision happens on the server. Those are the findings behind account takeover and fraud, and every one of them needs two working identities and a person deciding what to try next.

A signed document naming the application by bundle identifier or package name and version, the backend hosts and environments in scope, the accounts and roles supplied, the testing window, the permitted and excluded techniques, how test data will be handled and destroyed, and a named person who can approve scope changes during the test. If an agency built the app, their backend may not be yours to test - get authorization from whoever controls each system. No authorization permits testing an application you do not own, and neither app store terms nor a customer relationship creates that permission.

Only if the scope says so, and it should. A mobile test exercises the endpoints the app calls, from the app, with mobile-typical headers and tokens. A full API assessment reconciles the endpoint inventory from specifications, gateway logs and client artefacts, then tests authorization across every role and tenant. If the API is not in scope, the report must state that exclusion explicitly, because the most expensive mobile findings - an endpoint that trusts a client-supplied identifier, a token with no expiry, a check that exists only in the UI - live exactly there.

Share this article

You're viewing a cached version of this post. Updates may appear shortly.