📋 What Is It?
Insecure Authentication is the failure to establish who the user is in a way the client cannot fake. In mobile the temptation is structural: the app is right there, it has a login screen, and it feels natural to let it decide whether the user is authenticated. But the app runs on hardware the attacker owns - they can hook the check, edit local storage, or skip the app entirely and call the back end directly.
The category also covers the shortcuts mobile UX invites: 4-digit offline PINs, "remember me" tokens that never expire, device identifiers used as credentials, and biometric prompts whose result is a boolean rather than the unlock of a cryptographic key.
⚠️ Common Exploits
- Client-Side Login: credentials compared inside the app
- Local Flag Flip:
isLoggedIn=truewritten to preferences - Boolean Biometrics: success callback hooked with Frida
- Offline PIN Only: a 4-digit code checked on device, unlimited attempts
- Device ID as Credential: IMEI/UUID treated as proof of identity
- Immortal Sessions: tokens that never expire or cannot be revoked
- Weak Password Policy: mobile-friendly rules that permit trivial secrets
- Skip the App: the API is called directly, bypassing every screen
🔴 Attack Flow
↓
2. Look for checks that never leave the device
↓
3. Hook the method or edit local state to declare yourself logged in
↓
4. Or drop the app entirely and call the API with a crafted request
↓
5. IMPACT: Authenticated access without ever presenting a valid credential!
❌ Vulnerable Code
✅ Secure Code
✓ Prevention Checklist
- Authenticate on the server; the app only presents credentials and carries tokens
- Assume every client-side check can be bypassed - never make it the control
- Store tokens in the Keychain/Keystore, never a plain flag or file
- Bind biometric authentication to a cryptographic key (CryptoObject / LAContext)
- Treat a local PIN as convenience: it should unwrap a server-issued token
- Keep access tokens short-lived; rotate refresh tokens and support revocation
- Never use device identifiers, phone numbers, or IMEI as credentials
- Rate-limit and lock out on the server, including OTP verification
- Offer MFA and require re-authentication for sensitive operations
- Invalidate sessions server-side on logout, password change, and device loss
- Test the API directly, without the app, to see what it accepts
🔍 Detection & Tools
Dynamic:
Static & Identity:
How to Test:
- Hook the login and biometric callbacks - does the app unlock anyway?
- Flip local flags in preferences and relaunch
- Call the API directly with no app and see what is accepted
- Replay an old token after logout and after a password change
- Brute-force the PIN/OTP path and check for server-side limits
🌍 Real-World
These are documented incident classes - recurring patterns rather than single CVEs.
- Offline credential checks: apps that validate a password or PIN locally are unlocked with a one-line runtime hook.
- Biometric UI gating: "Face ID protected" screens that reveal data as soon as the success callback is forced true, because no key was involved.
- Device identifiers as credentials: back ends that trust a supplied device id return another user's data when the value is changed.
- Never-expiring "remember me" tokens: a token from a resold or stolen phone still authenticates months later.
- API-only bypass: flows enforced entirely in the UI are skipped by calling the endpoints directly.
📌 Quick Tips
- DO NOT authenticate on the device
- DO NOT gate access with a local boolean
- DO NOT use a device id as identity
- DO bind biometrics to a real key
- DO keep tokens short-lived and revocable
- DO test the API with the app removed
📜 Compliance
Related Standards:
- OWASP Mobile Top 10 2016 - M4
- Maps to M3:2024 Insecure Authentication/Authorization
- OWASP MASVS AUTH-1, AUTH-2, AUTH-3
- CWE-287 Improper Authentication
- CWE-306 Missing Authentication for Critical Function
- NIST SP 800-63B Digital Identity Guidelines