Mobile App Security Checklist Based on OWASP MASVS
Practice4 minInnovialabs editorial team
In short
Use MASVS as a checklist: keep secrets in Keychain or Keystore, pin certificates, detect rooted devices, obfuscate release builds, validate every deep link, and keep business logic, prices and keys on the server.
What MASVS is and how to use it
OWASP MASVS (Mobile Application Security Verification Standard) is an open standard that describes what a secure mobile app should do. It is grouped into control areas: STORAGE, CRYPTO, AUTH, NETWORK, PLATFORM, CODE, RESILIENCE and PRIVACY. Its companion, the MASTG testing guide, explains how to verify each item.
The main principle behind all of it: the app runs on a device you do not control. Anything shipped in the binary can be read, modified and replayed. The checklist below turns the standard into concrete tasks.
STORAGE: where data lives
- Store tokens, keys and passwords only in iOS Keychain or Android Keystore-backed storage. In Flutter, use a plugin such as
flutter_secure_storage, which wraps both. - Never put tokens in
UserDefaults,SharedPreferences, plain files or SQLite without encryption. - Do not log personal data or tokens, even in debug builds that might reach testers.
- Exclude sensitive files from cloud backups and hide sensitive screens from the app switcher snapshot.
- Clear the clipboard for one-time codes and disable autocorrect caching for secret fields.
NETWORK: protecting traffic
- HTTPS only. Keep App Transport Security on iOS and set
cleartextTrafficPermitted="false"on Android. - Use certificate or public key pinning for your own API, so a fake certificate installed on the device does not allow traffic interception.
- Android: Network Security Config with
<pin-set>. - iOS:
NSPinnedDomainsin Info.plist or a networking library with pinning. - Flutter: a custom
SecurityContextor an HTTP client plugin that supports pinning.
- Android: Network Security Config with
- Always pin at least two keys (current and backup) and plan rotation, or an expired certificate will lock users out until they update.
<domain-config>
<domain includeSubdomains="true">api.example.com</domain>
<pin-set expiration="2027-01-01">
<pin digest="SHA-256">base64-primary-key-hash=</pin>
<pin digest="SHA-256">base64-backup-key-hash=</pin>
</pin-set>
</domain-config>
AUTH: sessions and login
- Use short-lived access tokens and refresh tokens that the server can revoke.
- Biometrics should unlock a key in the secure hardware, not just return "true" to the app.
- Implement logout and token revocation on the server side.
RESILIENCE: root, jailbreak and tampering
- Detect rooted and jailbroken devices, hooking frameworks and debuggers. Decide the reaction by risk: a warning for a content app, blocked payments for a fintech app.
- Prefer platform attestation: Play Integrity API on Android and App Attest on iOS. The server verifies the result, not the app.
- Remember that local checks can be bypassed; they raise the cost of an attack, not make it impossible.
CODE: build hygiene
- Enable obfuscation and shrinking: R8/ProGuard on Android,
flutter build --obfuscate --split-debug-infofor Flutter. Keep the mapping files private for crash decoding. - Remove debug menus, test endpoints and verbose logging from release builds.
- Keep dependencies updated and scan them for known vulnerabilities.
PLATFORM: deep links and IPC
- Prefer verified links: Android App Links with
assetlinks.jsonand iOS Universal Links withapple-app-site-association. Custom schemes likemyapp://can be claimed by another app. - Validate every parameter of a deep link as untrusted input. A link must never trigger a payment, change settings or open an arbitrary URL in a WebView without confirmation.
- Do not export Android components (activities, receivers, providers) that do not need to be public.
- In WebViews, disable JavaScript bridges where they are not needed and load only your own domains.
What must stay on the server
| Never in the app | Why |
|---|---|
| Secret API keys for payments, SMS, AI services | They will be extracted from the binary |
| Price, discount and bonus calculation | The client can modify requests |
| Access checks and limits | Local checks can be patched out |
| Validation of purchases and subscriptions | Receipts must be verified with the store from the server |
The app is a convenient interface; the server is the source of truth.