CVE-2026-13788
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc |
modified |
Files Changed
chrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc
Patch
From 3c800c80b475241ebb081b77f401c49c0b3e1a84 Mon Sep 17 00:00:00 2001 From: Muyao Xu <[email protected]> Date: Mon, 15 Jun 2026 17:28:58 -0700 Subject: [PATCH] [Fullscreen] Fix potential UaF in ExclusiveAccessManagerAndroid This CL ensures the Java layer is notified when the C++ object is destroyed. Bug: 523119897 Change-Id: Iceb87e1d207251957346627ef82b0f500531db53 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7947577 Commit-Queue: Muyao Xu <[email protected]> Reviewed-by: Mike Wasserman <[email protected]> Cr-Commit-Position: refs/heads/main@{#1647206} --- diff --git a/chrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc b/chrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc index c4ac856..de667dd 100644 --- a/chrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc +++ b/chrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc @@ -163,6 +163,11 @@ } void ExclusiveAccessManagerAndroid::Destroy(JNIEnv* env) { + if (eac_) { + // Notify the Java counterpart to drop its native pointer before + // the C++ object is destroyed, preventing a use-after-free. + eac_->Destroy(env); + } delete this; }
Original Bug Report
Potential Use-After-Free in ExclusiveAccessContextAndroid during tab reparenting
Flapjack, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential Use-After-Free vulnerability exists in the Android Browser process due to incomplete JNI lifecycle synchronization. When ExclusiveAccessManagerAndroid is destroyed, its associated ExclusiveAccessContextAndroid is freed but fails to nullify its Java counterpart’s native pointer. Subsequent touch events on a surviving Tab can trigger JNI calls using this dangling pointer.
Affected files:
chrome/browser/ui/android/exclusive_access/exclusive_access_context_android.ccchrome/android/java/src/org/chromium/chrome/browser/ui/ExclusiveAccessContext.javachrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc
Estimated timestamp from git blame: 2026-05-20
Summary
A potential Use-After-Free (UAF) vulnerability exists in the Android implementation of ExclusiveAccessContextAndroid. When the ExclusiveAccessManagerAndroid is destroyed (e.g., during Activity teardown), it frees its ExclusiveAccessContextAndroid member. However, it fails to invoke the Destroy(JNIEnv*) method to notify the Java layer. Consequently, the Java ExclusiveAccessContext retains a dangling pointer to the freed C++ memory and leaks an ActivityTabTabObserver attached to the current Tab.
Because Tab objects frequently outlive the Activity (such as during screen rotation, multi-window moves, or tab reparenting), the leaked observer remains active. If the user touches the preserved tab, the observer’s onTouchDown() callback fires and makes a JNI call (onExclusiveAccessUserInput) using the dangling pointer, resulting in a UAF in the privileged Browser process.
Potential Trigger Steps
Note: These are suggested steps based on code analysis; our tooling agent does not have the ability to run a working Proof of Concept (PoC).
- An attacker hosts a malicious webpage and entices a user to visit it.
- The webpage requests fullscreen mode (
document.documentElement.requestFullscreen()), triggering the creation of the JavaExclusiveAccessManagerand its C++ counterparts. - During initialization, a raw C++ pointer is passed to Java as a
jlong(mNativeExclusiveAccessContextAndroid), and anActivityTabTabObserveris registered on the activeTab. - The attacker triggers a configuration change or tab reparenting event that causes the current
Activityto be destroyed while preserving theTab. ExclusiveAccessManagerAndroid::Destroydeletes itself and itsstd::unique_ptr<ExclusiveAccessContextAndroid> eac_, freeing the C++ context. However, it misses a call toeac_->Destroy(env).- The Java
ExclusiveAccessContext.destroy()is never called. ThemNativeExclusiveAccessContextAndroidpointer remains non-zero, and the observer is never unregistered from theTab. - The attacker uses JavaScript in the surviving Tab to perform heap grooming, replacing the freed
ExclusiveAccessContextAndroidwith attacker-controlled data. - The attacker prompts the user to interact with the webpage (e.g., touching a button).
- The touch event triggers
onTouchDown()on the leaked Java observer, which makes a JNI call using the dangling pointer. - The JNI wrapper casts the
jlongto a raw C++ pointer and callsExclusiveAccessContextAndroid::OnExclusiveAccessUserInput(JNIEnv*). - The method accesses the attacker-forged object, dereferences its
exclusive_access_bubble_pointer, and calls the virtual methodShow(), allowing the attacker to hijack the vtable and achieve Remote Code Execution (RCE).
Impact
This vulnerability allows for arbitrary Remote Code Execution (RCE) in the privileged Browser process, effectively bypassing the sandbox. MiraclePtr (BackupRefPtr) does not protect against this UAF because the reference crossing the JNI boundary is held as a primitive jlong rather than a raw_ptr, and the C++ side drops all raw_ptr references upon destruction, allowing PartitionAlloc to fully free the memory.
Suggested Fix
Explicitly invoke the Destroy method on the ExclusiveAccessContextAndroid object before it is deleted.
In chrome/browser/ui/android/exclusive_access/exclusive_access_manager_android.cc:
void ExclusiveAccessManagerAndroid::Destroy(JNIEnv* env) {
if (eac_) {
eac_->Destroy(env);
}
delete this;
}
Alternatively, call Destroy() from within ExclusiveAccessContextAndroid::~ExclusiveAccessContextAndroid(), but ensure a valid JNIEnv is correctly attached or retrieved.
Evaluated with Chrome root at commit: 2155cb00003ec35716a76ed3246eae995f87b7ff
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.