Skip to content
CyberXplore - Xplore the Unseen

The Mobile App Pentest Checklist: OWASP MASVS in Practice

cyberxploreBy cyberxplore11 min read

A practitioner's mobile app penetration testing checklist mapped to OWASP MASVS: insecure storage, weak crypto, cert pinning, and how we actually test it.

The Mobile App Pentest Checklist: OWASP MASVS in Practice

Give me an APK and five minutes and I will usually hand you back something the developers did not want shipped. Unzip it, run it through jadx, grep the decompiled source for password, secret, or api_key, and watch the hits scroll past. A hardcoded token here. A staging hostname that still answers there. A TODO from a sprint nobody remembers writing.

That is where a lot of mobile app penetration testing starts, and more often than it should, it is where the first real finding comes from too. The client runs on hardware you do not own. An attacker can take the binary apart on their own bench, at their own pace, with no rate limiting and nobody watching. Web-app instincts do not survive contact with that reality.

We anchor every engagement to the OWASP Mobile Application Security Verification Standard, MASVS, and turn it into a checklist we run against real Android and iOS builds. Here is how that actually works.

Key takeaways

  • Mobile app penetration testing pairs static analysis of the decompiled binary with dynamic analysis of a running, instrumented app, because the client is fully in the attacker’s hands.
  • OWASP MASVS groups controls into storage, crypto, authentication, network, platform interaction, code quality, and resilience; the OWASP MASTG gives you concrete test cases for each.
  • The serious findings we report most are insecure local data storage, misused cryptography, and backend authorization flaws that surface once you defeat certificate pinning.
  • Certificate pinning slows a tester down. It does not make an app secure. If the server trusts the client, bypassing the pin just reveals the real bugs underneath.
  • MASVS defines verification levels (L1 baseline, L2 defense-in-depth, R resilience), so scope the test to what the app’s risk actually warrants instead of testing everything to the same depth.

What is MASVS, and why base a mobile pentest on it?

MASVS is OWASP’s answer to a simple question: what should a secure mobile app actually do? It is the backbone of any serious mobile app penetration testing engagement. Requirements are split into control groups – storage (MASVS-STORAGE), cryptography (MASVS-CRYPTO), authentication and session management (MASVS-AUTH), network communication (MASVS-NETWORK), platform interaction (MASVS-PLATFORM), code quality (MASVS-CODE), and resilience against reverse engineering (MASVS-RESILIENCE).

Its companion, the OWASP Mobile Application Security Testing Guide (MASTG), is where the standard earns its keep. MASVS says the app “should not store sensitive data unencrypted.” MASTG tells you which files to pull, which APIs leak, and how to prove it. We use MASVS as the coverage map so nothing gets skipped, and MASTG as the how-to for each control.

One thing worth saying plainly: a checklist is a floor, not a ceiling. We run the MASVS categories to guarantee coverage, then spend the rest of the engagement chasing the app-specific logic no standard could predict. The interesting bugs almost always live in the business logic and the backend, not in whether the app ticks a generic box.

How do you test a mobile app? Static plus dynamic

Every job is two passes over the same target: the app at rest, and the app while it runs. Skip either and you miss half the picture.

Static analysis: read the binary

On Android we decompile first. apktool gets you the manifest and resources; jadx turns the DEX back into readable Java. On iOS you are working with a decrypted IPA, class dumps, and the Info.plist. The point of the static pass is to understand the app before you run it, and to catch things that never show up in traffic.

A typical opening move on Android:

apktool d target.apk -o target_src
jadx -d target_out target.apk

# hunt for obvious secrets and dangerous config
grep -rniE "api[_-]?key|secret|password|token|BEGIN RSA" target_out/
grep -rn "usesCleartextTraffic" target_src/AndroidManifest.xml

Then we read the AndroidManifest for exported components: activities, services, broadcast receivers, and content providers marked android:exported="true" with no permission guard. An exported activity that takes an intent and loads a URL into a WebView is a classic path to task hijacking or WebView injection. On iOS the equivalent hunt is custom URL schemes and Universal Links declared in the plist, because those are attacker-reachable entry points too.

Network config matters here as well. usesCleartextTraffic="true", or a permissive network_security_config.xml that trusts user-added CAs, tells you cleartext or interception is on the table before you even open a proxy.

Dynamic analysis: run it and watch

Dynamic analysis needs a rooted Android device or a jailbroken iPhone, or their emulator equivalents. Our go-to instrumentation is Frida with Objection layered on top. Frida hooks methods at runtime, dumps arguments, and rewrites return values. Objection gives us quick wins – listing keychain entries, dumping SharedPreferences, disabling common pin checks – without hand-writing a hook for every one.

We proxy all traffic through Burp Suite. The moment the app talks to its backend, the mobile-specific work mostly ends and standard API testing begins: authorization checks, IDOR on object identifiers, mass assignment, replaying another user’s requests. Getting a clean view of that traffic is priority one, which is exactly why certificate pinning matters so much to the workflow.

What are the most common mobile app pentest findings?

The same handful of issues recur across engagements. They map cleanly onto the MASVS categories, which is a decent hint that the standard was built on real pain rather than theory.

Insecure data storage (MASVS-STORAGE)

This is the finding we report most. Apps cache far more than developers realize. On Android we pull the sandbox and read through SharedPreferences XML, SQLite databases, and files under the internal data directory:

adb shell run-as com.example.app ls -la /data/data/com.example.app/
adb shell run-as com.example.app cat shared_prefs/*.xml

Session tokens. Full credentials. PII. Occasionally payment data, sitting in plaintext SharedPreferences or an unencrypted SQLite table. On iOS the same class of bug shows up in NSUserDefaults, plist files, Core Data stores, and Keychain items saved with a weak accessibility class like kSecAttrAccessibleAlways. Anything readable on a lost or malware-infected device is a real exposure, and it maps to CWE-312, cleartext storage of sensitive information.

Weak or misused cryptography (MASVS-CRYPTO)

The crypto category is rarely about broken math. It is about misuse. Hardcoded keys pulled straight from the decompiled source. ECB mode, where repeating plaintext blocks leak structure in the ciphertext – that broken-algorithm choice is CWE-327. Static or null IVs. Homegrown “encryption” that turns out to be Base64 with extra steps, and Base64 is encoding, not protection.

Frida is perfect for confirming this live. Hook the cipher setup and print the key and IV as the app runs:

Java.perform(function () {
  var Cipher = Java.use("javax.crypto.Cipher");
  Cipher.init.overload("int", "java.security.Key").implementation = function (mode, key) {
    console.log("[cipher] alg=" + this.getAlgorithm() +
                " key=" + Java.use("android.util.Base64").encodeToString(key.getEncoded(), 0));
    return this.init(mode, key);
  };
});

When the key that “protects” your data prints to the console on app launch, the argument about theoretical strength is over.

Backend authorization and session flaws (MASVS-AUTH)

Once traffic is visible, the server carries the trust, and that is where the high-severity bugs hide. Tokens that never expire. Predictable session identifiers. Authorization decisions made client-side instead of server-side. If the app hides an admin button but the API cheerfully answers the admin call from a normal account, that is a critical, and no amount of client hardening fixes it.

How do you bypass certificate pinning?

You bypass pinning by hooking the code that performs the pin check and forcing it to pass – usually with Frida or Objection – so your proxy CA is trusted again. Objection ships a one-liner:

objection -g com.example.app explore
# then, in the Objection prompt:
android sslpinning disable

For apps with a custom pinning implementation or native-code checks, the generic bypass fails and you drop into a targeted Frida script that hooks the specific TrustManager, the OkHttp CertificatePinner, or the native SSL_CTX_set_custom_verify path. On iOS you are usually hooking TrustKit or the app’s own trust-evaluation logic around SecTrustEvaluate.

Here is the opinion part. Pinning is a speed bump, not a control. It raises the cost for a casual attacker and buys time against automated tooling, which is genuinely useful and worth implementing. But if defeating the pin reveals an API with broken authorization, the pinning was cosmetic. We test every app as if pinning is already defeated, because a motivated attacker with the binary and a rooted device will defeat it. MASVS files pinning under resilience for exactly that reason: it is defense-in-depth, not a substitute for a backend that enforces its own rules.

How do you fix these issues?

Mostly by respecting the platform. Use OS-provided secure storage instead of rolling your own: Android Keystore and EncryptedSharedPreferences via Jetpack Security, and the iOS Keychain with a sensible accessibility class such as kSecAttrAccessibleWhenUnlockedThisDeviceOnly. Never park long-lived secrets in SharedPreferences or NSUserDefaults.

For crypto, reach for vetted high-level libraries rather than raw cipher calls. Google’s Tink is a good default because it makes the safe choice the easy one. Do not ship keys inside the app; derive or provision them at runtime and keep the real trust decisions on the server. Treat the client as untrusted, end to end – every authorization and validation check that matters must be enforced server-side, because the mobile client can and will be tampered with. Add pinning and anti-tamper as extra layers once the fundamentals are right, not before.

How CyberXplore helps

Our mobile application penetration testing service runs the full MASVS-mapped methodology described here against your Android and iOS builds: static analysis of the decompiled binary, dynamic analysis on instrumented devices, pinning bypass, and a hard look at the backend APIs the app leans on. You get a report that ranks findings by real business impact, with reproduction steps a developer can follow and a retest once fixes land, so the fix is verified and not just claimed. Prepping for an app-store review, a customer security questionnaire, or a compliance audit? We align the engagement to the right MASVS verification level. Get a quote and tell us about your app; we will scope it honestly.

FAQ

How long does a mobile app penetration test take?

A focused single-platform app usually runs one to two weeks of testing, depending on feature count, the size of the API surface, and whether both Android and iOS are in scope. Apps with heavy backend logic take longer, because most of the serious findings live in server-side authorization, and that is where the hours go once traffic is visible.

Do you need the source code to test a mobile app?

No. We work fine in black-box mode from just the compiled APK or IPA, since decompilation is part of the job anyway. That said, a gray-box test where you share source and test accounts finds more and finds it faster, because we spend testing hours on real bugs instead of reverse engineering. We recommend gray-box for the best coverage per dollar.

What is the difference between MASVS and MASTG?

MASVS is the standard: it defines the security requirements a mobile app should meet, grouped into categories and verification levels. MASTG is the testing guide: it gives testers concrete techniques, tool usage, and test cases to verify each requirement. In practice we use MASVS as the coverage checklist and MASTG as the procedure manual.

Does certificate pinning make my app secure?

No. Pinning is a resilience control that slows interception and automated attacks, which is worth having, but a determined tester with a rooted device will bypass it. It does nothing for insecure local storage, weak crypto, or broken backend authorization. Treat it as one layer on top of an app that is already secure without it.

How often should we pentest a mobile app?

At least annually, and after any significant change such as a new authentication flow, a payment feature, or a major backend integration. Mobile apps ship fast, and each release can reintroduce old issues or add new attack surface, so a point-in-time test only tells you about the build you tested. Many teams pair an annual full test with lighter retests on major releases.

Work with CyberXplore

Web Application Penetration Testing

Seeing this risk in your own systems? Our senior testers find and prove exactly these issues, then hand you a clear path to fix them.

Related articles

Turn these insights into an engagement

Get a senior-led penetration test scoped to your stack - findings you can act on, not a checklist.

  • Free retest on every fix
  • Scoped quote within 24 hours
  • Senior-only testers
  • ISO 27001
  • ISO 9001
  • OSCP
  • CRTP
  • CREST
Get a Quote