A logic error in exitKeyguardAndFinishSurfaceBehindRemoteAnimation allows local privilege escalation by bypassing the lockscreen without any user interaction or additional privileges.
# Android Lockscreen Bypass: What You Need to Know
Your Android phone's lockscreen is supposed to be like a bouncer at an exclusive club — it checks your fingerprint or PIN before letting anyone in. A newly discovered flaw essentially tricks that bouncer into stepping aside, allowing someone with physical access to your phone to unlock it without knowing your password.
Here's what makes this serious. The vulnerability doesn't require the attacker to be technical or to have special access. Any app or process already running on your device could potentially exploit it. Think of it like a security guard who's willing to open the door if someone just asks politely enough.
The good news is that no one is actively using this attack in the wild yet. But the window between when a vulnerability becomes public and when hackers start exploiting it is usually measured in days or weeks, not months.
Who should worry most? Anyone with a device they share with others, a phone they leave unattended in public spaces, or anyone at risk of physical device theft. If someone steals your phone or borrows it briefly, they could potentially access your messages, photos, banking apps, and personal data without your knowledge.
What you can do right now: First, keep your phone with you at all times — even at home, consider keeping it in a secure location rather than on a table. Second, check for Android security updates immediately and install them as soon as they're available. Third, use a strong PIN or complex biometric (face recognition plus PIN is better than fingerprint alone). Google will likely release a patch soon, so don't delay installing it when it arrives.
Want the full technical analysis? Click "Technical" above.
CVE-2025-48602 is a logic error in KeyguardViewMediator.java within Android's System UI / WindowManager subsystem. The flaw lives specifically in exitKeyguardAndFinishSurfaceBehindRemoteAnimation(), a method responsible for coordinating the animation handoff that occurs when the keyguard (lockscreen) is dismissed. A race between animation state and keyguard state validation means an attacker can drive the device into a code path that tears down the lockscreen surface without ever authenticating. CVSS 8.4 (HIGH), no additional execution privileges required, no user interaction needed.
Disclosed in the Android Security Bulletin for March 2026, this vulnerability affects the Android framework layer and is exploitable by any local application or physical attacker able to manipulate window/animation state on the device.
Root cause:exitKeyguardAndFinishSurfaceBehindRemoteAnimation() finishes the lockscreen surface animation and signals keyguard dismissal without re-validating that the keyguard is still in the authenticated state, allowing a mid-animation state flip to promote an unauthenticated session to full device access.
Affected Component
Package : com.android.systemui / android.policy
File : frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
Method : exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean)
Class : KeyguardViewMediator
Layer : System UI / WindowManager Policy
Process : system_server + com.android.systemui
Privilege: SYSTEM_UID – direct path to full device unlock
Root Cause Analysis
The keyguard dismissal flow in modern Android involves a two-phase remote animation handoff. Phase 1: the app-side remote animator plays the "surface behind" animation (the content under the lockscreen sliding into view). Phase 2: once the animation finishes, exitKeyguardAndFinishSurfaceBehindRemoteAnimation() is called to finalize the keyguard state and release the surface.
The logic error is that the finalization path checks a stale cached flag (mKeyguardDoneForFinishSurfaceBehindRemoteAnimation) set at animation start time, rather than re-querying live keyguard authentication state at animation end time. If the device re-locks during the animation (e.g., screen timeout fires, security policy triggers a re-lock, or an attacker artificially extends the animation duration), the cached flag remains true while the actual keyguard is now locked — and the finalization path proceeds unconditionally to dismiss.
// KeyguardViewMediator.java — VULNERABLE (pre-patch)
private void exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean cancel) {
if (DEBUG) {
Log.d(TAG, "exitKeyguardAndFinishSurfaceBehindRemoteAnimation cancel=" + cancel);
}
// BUG: mKeyguardDoneForFinishSurfaceBehindRemoteAnimation is set once at
// animation START (handleStartKeyguardExitAnimation). It is never
// invalidated if the device re-locks mid-animation. We proceed to call
// finishSurfaceBehindRemoteAnimation() and notifyKeyguardExitDone()
// purely on this stale boolean.
if (mKeyguardDoneForFinishSurfaceBehindRemoteAnimation) {
// BUG: no live re-check of isKeyguardSecure() / isDeviceLocked() here
finishSurfaceBehindRemoteAnimation(cancel);
mKeyguardStateController.notifyKeyguardDoneFading();
// This is the critical call — it signals WM that keyguard is gone.
// After this returns, the lockscreen surface is destroyed and the
// underlying app window receives full input focus.
mKeyguardUnlockAnimationController.notifyKeyguardExitAnimationFinished();
} else {
cancelKeyguardExitAnimation();
}
// State is cleaned up AFTER the unlock signal — too late to gate on it
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation = false;
mSurfaceBehindRemoteAnimationRunning = false;
}
// Where the stale flag is SET (animation start — separate code path):
private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
// ...
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation =
mKeyguardStateController.isKeyguardDone(); // cached here — never refreshed
// ...
}
The window between animation start and exitKeyguardAndFinishSurfaceBehindRemoteAnimation() being called can be stretched. The RemoteAnimationRunner callback timing is app-controlled via the IRemoteAnimationFinishedCallback binder interface — a malicious or compromised app running the animation can simply delay calling finishedCallback.onAnimationFinished(), providing an arbitrarily large TOCTOU window during which a re-lock can be forced.
Exploitation Mechanics
EXPLOIT CHAIN — CVE-2025-48602
1. Attacker app registers as a RemoteAnimationRunner for keyguard exit
transitions via ActivityOptions or WindowManager shell APIs.
(Requires no special permission on affected builds — available to
foreground apps triggering intent-based keyguard dismissal flows.)
2. User (or attacker) initiates a keyguard exit that triggers the
remote animation: e.g., launching an activity with FLAG_DISMISS_KEYGUARD
from a notification or direct ADB invocation.
3. System calls IRemoteAnimationRunner.onAnimationStart() → app receives
control of the surface animation. At this point:
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation = TRUE (cached)
mKeyguardStateController.isDeviceLocked() = FALSE (unlocking)
4. Attacker deliberately does NOT call finishedCallback.onAnimationFinished().
Animation hangs indefinitely — system is waiting on the binder callback.
5. Attacker triggers a device re-lock:
- Send broadcast: com.android.internal.policy.action.LOCK_NOW
- Or: DevicePolicyManager.lockNow() from a Device Admin app
- Or: Wait for screen timeout (default 30s on many devices)
After re-lock:
mKeyguardStateController.isDeviceLocked() = TRUE (device is locked)
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation = TRUE (STALE)
6. Attacker now calls finishedCallback.onAnimationFinished() via binder.
System routes this to exitKeyguardAndFinishSurfaceBehindRemoteAnimation().
7. The stale TRUE flag passes the if-check unconditionally:
finishSurfaceBehindRemoteAnimation(false) → surface destroyed
notifyKeyguardExitDone() → WM told keyguard is gone
notifyKeyguardExitAnimationFinished() → app window gets focus
8. Lockscreen surface is torn down. Device is at the home screen /
last active app. Full device access achieved with no authentication.
Effective privilege: whoever owns the foreground session (USER_CURRENT).
Memory Layout
This is a logic/state bug rather than a memory corruption bug, so the relevant "layout" is the keyguard state machine. The following shows the two diverged state views that create the vulnerability window:
The fix adds a live re-validation of keyguard authentication state at the point of finalization, discarding the cached flag as the sole gate. If the live state shows the device has re-locked, the finalization path is aborted and cancelKeyguardExitAnimation() is called instead.
// BEFORE (vulnerable):
private void exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean cancel) {
if (mKeyguardDoneForFinishSurfaceBehindRemoteAnimation) {
// No live state check — proceeds on stale cached boolean
finishSurfaceBehindRemoteAnimation(cancel);
mKeyguardStateController.notifyKeyguardDoneFading();
mKeyguardUnlockAnimationController.notifyKeyguardExitAnimationFinished();
} else {
cancelKeyguardExitAnimation();
}
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation = false;
mSurfaceBehindRemoteAnimationRunning = false;
}
// AFTER (patched — March 2026 security update):
private void exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean cancel) {
// PATCH: re-query live device lock state at finalization time.
// If the device has re-locked since the animation started, the cached
// flag is no longer trustworthy — abort the exit and cancel.
final boolean keyguardStillDone =
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation
&& !mKeyguardStateController.isDeviceLocked(); // ADDED: live check
if (keyguardStillDone) {
finishSurfaceBehindRemoteAnimation(cancel);
mKeyguardStateController.notifyKeyguardDoneFading();
mKeyguardUnlockAnimationController.notifyKeyguardExitAnimationFinished();
} else {
// Device re-locked mid-animation — tear down the animation and
// force the lockscreen to re-present itself.
cancelKeyguardExitAnimation();
// PATCH: explicitly re-show keyguard to handle the re-lock case
mKeyguardViewControllerLazy.get().show(null /* options */);
}
mKeyguardDoneForFinishSurfaceBehindRemoteAnimation = false;
mSurfaceBehindRemoteAnimationRunning = false;
}
The secondary fix — calling show(null) when the re-lock is detected — closes a further gap where cancelling the exit animation without explicitly re-presenting the keyguard could leave the screen in a partially-unlocked visual state.
Detection and Indicators
LOGCAT INDICATORS (pre-patch, during exploitation):
-----------------------------------------------------
KeyguardViewMediator: exitKeyguardAndFinishSurfaceBehindRemoteAnimation cancel=false
KeyguardViewMediator: notifyKeyguardDoneFading
WindowManager : finishKeyguardExitAnimation — keyguard gone
# Notable absence: no KeyguardSecurityContainer authentication success log
ANOMALY PATTERNS TO HUNT:
- IRemoteAnimationRunner.onAnimationStart() called but
IRemoteAnimationFinishedCallback.onAnimationFinished() delayed > 5s
- KeyguardService reports LOCKED state while WM reports keyguard GONE
- com.android.systemui KeyguardViewMediator logs showing
"exitKeyguard" without preceding "KeyguardDismissed by auth"
- Unexpected wakelock pattern: device re-locks then immediately shows
home screen without biometric/PIN input event
RELEVANT SELINUX / AUDIT EVENTS:
- avc: granted { ... } for system_server accessing keyguard_service
immediately followed by keyguard surface destruction without
activity on input subsystem (no touch/biometric events)
Remediation
Apply the March 2026 Android Security Bulletin patch (2026-03-01 SPL or later). Verify with:
adb shell getprop ro.build.version.security_patch
# Must return: 2026-03-01 or later
Mitigations for unpatched devices:
Disable remote animation overrides for keyguard exit transitions via MDM policy where possible.
Set aggressive screen timeout and immediate lock policy (REQUIRE_PASSWORD_ON_WAKE) — this narrows but does not eliminate the window.
Enterprise environments: enforce Device Admin lock policy with setMaximumTimeToLock(0); this reduces the attacker-controlled re-lock window to zero if the attacker cannot call lockNow() themselves.
Monitor for the logcat anomaly patterns above via on-device security agents.
There is no evidence of in-the-wild exploitation at time of publication. The requirement for a foreground app capable of registering a RemoteAnimationRunner limits the attack surface compared to fully zero-interaction lockscreen bypasses, but the CVSS 8.4 rating correctly reflects that no user authentication is required and the impact is complete lockscreen bypass.