This issue CVE-2026-0091 has been fixed for Android 14+ in June 2026 Android Security Bulletin. Click here to see the patch

The following is copied from my repo https://github.com/canyie/TransitionPlayer for backup purposes. For more info such as PoC code, please check the original repo.

Writeup

TODO

I’ll complete the writeup when I got a little free time

But before that I have to fight against school work and exams

I decided to complete the section before exams are finished

Good luck to me 😇

Introduction to IApplicationThread

IApplicationThread is a private callback provided to system from apps so that system can use it to send commands (load specified app, notify changes of component lifecycle, etc) to app

It is intended to only usable from system, so there are no permission checks, and security is guaranteed solely by the fact that the object is not obtained by a malicious process. This sounds somewhat similar to the concept of “cookies” or “tokens” in web. Such access control model is called as Capability-based Security

If someone else managed to obtain an IApplicationThread from other processes, they can send arbitrary commands and the victim app would just process the fabricated commands like they were generated by system. In a previous exploit of CVE-2022-20452 the trick was used to perform arbitrary code execution

RemoteTransition

While IApplicationThread should only be passed to system process, it can be unexpectedly sent out of system_server

No one would implement an getIApplicationThreadForApp(String packageName) API that is exposed to any one, it is an obvious security violation

But if IApplicationThread is wrapped in another object and the outer wrapper object gets sent, it is a more likely scenario

RemoteTransition is such a wrapper which contains an IApplicationThread in order to boost priority of app that is running an animation

One user of that API is Launcher3, the default home application on AOSP and Pixel devices, which creates an ActivityOptions using a RemoteTransition and then pass it to startActivity()

While Launcher3 itself does not expose the object to untrusted factors, the system_server sometimes does

CVE-2022-20419 occurred because system_server forwarded caller-passed ActivityOptions to launched app but forgot to strip RemoteTransition, allowing launched app to receive it and load arbitrary code inside launcher process

TransitionPlayer

During shared-element transition animation, a lot of work has to done and communications need to happen between WMCore and WMShell, where WM means Window Manager

You can read this article to understand WMShell

As WMCore and WMShell runs in different processes (WMCore runs in system_server and WMShell runs in SystemUI), they utilize the Binder mechanism to talk with each other

WMCore exposed a Binder registerTransitionPlayer API and WMShell uses it to register its own binder

When animation is started, WMCore calls requestStartTransition and TransitionRequestInfo is passed to remote, which includes the initial RemoteTransition

So if we can replace the transition player, we will be able to retrieve Launcher’s IApplicationThread and achieve arbitrary code execution inside a privileged process

However, registerTransitionPlayer is protected by MANAGE_ACTIVITY_TASKS permission which 3rd party app can’t get

But adb shell can also run untrusted user code, and the shell is granted MANAGE_ACTIVITY_TASKS permission, so luckily we can launch attack from adb shell

Impact

It’s a funny question that what can attackers do through this vulnerability

As most permissions granted to Launcher are also held by adb shell, attackers who already able to execute code under shell identity don’t need to exploit this vulnerability to compromise device

This is more like an educational example project for learning IApplicationThread than an exploit that can be used by malicious app

However, someone may be still be interested in this one

For example, this can be used to extract Launcher’s private files, which can be useful in forensic analysis for malicious Launcher apps without rooting device. Previously this was achieved by exploiting CVE-2024-31317, and my finding reveals another method after the previous one was fixed

This also allows users to use Fabricated Runtime Resources Overlay (FRRO) without first rooting their device, so rootless custom themes is back after CVE-2021-39630 was patched. My exploit has demonstrated this by setting android:integer/config_multiuserMaximumUsers to 100

In addition, the Launcher also hosts the Recents screen component by default and thus is allowlisted for some privileged actions. I think the Launcher is allowed to start arbitrary activity in an existing task regardless of exported/permission settings of launched Activities which might be wanted by some device management tool apps, although I haven’t tested it myself

Test

https://github.com/canyie/TransitionPlayer

Build the project, install generated apk file (if you use the Run button inside Android Studio, turn on “Always install with package manager”)

Run the following command on PC

1
adb shell app_process '-Djava.class.path=$(pm path top.canyie.transitionplayer | cut -c9-) /system/bin top.canyie.transitionplayer.Main'

Then launch an arbitrary app by tapping its icon from the launcher

A notification should be sent from the launcher app, and if you are on Android 14+, a fabricated overlay will be injected into the system, so adb shell cmd overlay lookup android android:integer/config_multiuserMaximumUsers should return 100

Fixes