CVE-2026-10005
Overview
Background
- `AppShimApplication`
- the
NSApplicationsubclass used by Chrome’s macOS app shim process, including PWAs (app_shim_application.mm:11). - `_selectWindow:`
- an AppKit action sent when the user picks a window from the Dock menu’s automatic window list (
app_shim_application.mmdiff, added guard). - Dock menu window list
- AppKit snapshots the open windows when the Dock menu is shown and keeps raw pointers to those
NSWindows while the menu is up.
Root Cause Analysis
Pre-fix, AppShimApplication (app_shim_application.mm:11-68) implements several NSApplication overrides but has no -sendAction:to:from: override, so every action — including _selectWindow: from the Dock menu — is dispatched straight to AppKit. The invariant required for Dock-menu window selection is that the target window still exists when the action fires, but AppKit’s Dock menu holds raw pointers to the windows it snapshotted and does not drop them if a window is closed while the menu is open. If a window is destroyed (e.g. a PWA closing a popup) while its Dock-menu entry persists, selecting that entry dispatches _selectWindow: to a freed NSWindow, i.e. an Objective-C message send on freed memory.
The fix adds a -sendAction:to:from: override (app_shim_application.mm diff): when anAction == @selector(_selectWindow:), it iterates for (NSWindow* window in [self windows]) comparing each against aTarget by pointer, and if no match is found it returns NO instead of calling super. The comment notes it deliberately avoids -[NSArray containsObject:] “because |aTarget| may be a freed object,” comparing raw pointers rather than messaging the target. This duplicates the guard that already existed in the browser’s application subclass, closing the gap for the shim process; a follow-up CL is noted to refactor the shared logic.
NSApplication subclass was missing the browser’s _selectWindow: validation, so a stale Dock-menu window pointer was dispatched without a liveness check; the fix validates the target against the live window list and short-circuits when it is gone.Attack Path
- Open a shim window A PWA opens a secondary window in the app shim process. (inferred trigger per reporter)
- Show the Dock menu The user right-clicks the shim’s Dock icon, so AppKit snapshots the window list including that window.
- Close the window
While the menu is open, the PWA closes the window, freeing the underlying
NSWindow. (inferred that JS close frees it) - Select the stale entry
Choosing the closed window’s menu entry sends
_selectWindow:to the freed object; pre-fix this reaches AppKit with no liveness check (app_shim_application.mmhad nosendAction:to:from:override). - Reclaim the memory An attacker who grooms the heap to reoccupy the freed slot could influence the dispatch. (inferred)
Impact Assessment
NSWindow in the app shim process, which the advisory notes runs unsandboxed on macOS. The advisory rates this high severity with no in-the-wild exploitation. Escalation from the use-after-free to code execution is (inferred) from the reporter; the shown code only establishes the missing liveness guard.Changed Functions
| Function | Change | Notes |
|---|---|---|
forchrome/app_shim/app_shim_application.mm |
modified | |
ifchrome/app_shim/app_shim_application.mm |
modified |
Files Changed
chrome/app_shim/app_shim_application.mm
Audit Directions
- Subclass parity for security guardsWhen one
NSApplication/platform subclass adds a safety override, audit sibling subclasses (here the shim) for the same guard. - AppKit raw-pointer snapshotsTreat any AppKit feature that caches window/object pointers (Dock menu, services) as a source of stale pointers across async teardown.
- Validate action targets before dispatchShort-circuit actions whose target may have been freed by checking a live collection with pointer comparison rather than messaging the target.
Patch
From 6c5b35aa509605188466f9d3a0472f345866be8b Mon Sep 17 00:00:00 2001
From: Marijn Kruisselbrink <mek@chromium.org>
Date: Mon, 18 May 2026 13:06:42 -0700
Subject: [PATCH] Fix Use-After-Free in AppShimApplication via Dock Menu
When a window is closed while the Dock menu is open, selecting it from
the Dock menu triggers the '_selectWindow:' action on a freed window
pointer. Short-circuit this action by validating the target window
before forwarding it to super.
This duplicates logic from CrBrowserApplication, but this will be
refactored in a follow-up CL by adding a common base class.
Bug: 513750089
Change-Id: I8aaa24e1298ffef543f3fa4a2b09896e9d7bab2e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7855918
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1632360}
---
diff --git a/chrome/app_shim/app_shim_application.mm b/chrome/app_shim/app_shim_application.mm
index 319232f..055a589 100644
--- a/chrome/app_shim/app_shim_application.mm
+++ b/chrome/app_shim/app_shim_application.mm
@@ -57,6 +57,31 @@
return [super accessibilitySetValue:value forAttribute:attribute];
}
+- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender {
+ // The Dock menu contains an automagic section where you can select
+ // amongst open windows. If a window is closed via JavaScript while
+ // the menu is up, the menu item for that window continues to exist.
+ // When a window is selected this method is called with the
+ // now-freed window as |aTarget|. Short-circuit the call if
+ // |aTarget| is not a valid window.
+ if (anAction == @selector(_selectWindow:)) {
+ // Not using -[NSArray containsObject:] because |aTarget| may be a
+ // freed object.
+ BOOL found = NO;
+ for (NSWindow* window in [self windows]) {
+ if (window == aTarget) {
+ found = YES;
+ break;
+ }
+ }
+ if (!found) {
+ return NO;
+ }
+ }
+
+ return [super sendAction:anAction to:aTarget from:sender];
+}
+
- (NSAccessibilityRole)accessibilityRole {
AppShimDelegate* delegate =
base::apple::ObjCCastStrict<AppShimDelegate>(NSApp.delegate);
Original Bug Report
Potential Use-After-Free in unsandboxed AppShimApplication via Dock Menu
Project Fortify, 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: AppShimApplication lacks a security guard in sendAction:to:from: that exists in BrowserCrApplication to prevent a Use-After-Free (UAF) condition. This allows a malicious Progressive Web App (PWA) to potentially trigger memory corruption and code execution in the unsandboxed app shim process. The vulnerability occurs when a window is closed while the macOS Dock menu is displaying it, leading to a stale pointer dispatch.
Affected files:
chrome/app_shim/app_shim_application.mmchrome/app_shim/app_shim_application.h
Estimated timestamp from git blame: 2019-01-29
Description
In Chromium on macOS, BrowserCrApplication (the NSApplication subclass for the browser process) overrides -[NSApplication sendAction:to:from:] to implement a security guard against a known Use-After-Free (UAF) condition in AppKit’s auto-generated Dock-menu window list.
When a user right-clicks an application’s Dock icon, AppKit snapshots the window list to populate the menu. If a window is subsequently closed (e.g., via JavaScript) while the menu is still open, the menu continues to hold a raw pointer to the now-freed NSWindow. Selecting that window from the menu causes AppKit to call _selectWindow: on the freed object. BrowserCrApplication prevents this by verifying that the target window still exists in the application’s window list before dispatching the action.
AppShimApplication, the NSApplication subclass used by app shims (including Progressive Web Apps), lacks this override and the corresponding guard. Consequently, selecting a closed window from a PWA’s Dock menu results in a potential wild-pointer dispatch via objc_msgSend on the freed memory of a NativeWidgetMacNSWindow object.
Impact
The app shim process runs unsandboxed on macOS (Sandbox::kNoSandbox as defined in sandbox/policy/sandbox_type.cc). By reclaiming the memory of the freed NativeWidgetMacNSWindow with attacker-controlled data, an attacker could potentially gain control of the Objective-C isa pointer. This leads to a potential Remote Code Execution (RCE) primitive within the unsandboxed process, effectively allowing a compromise of the user environment from a PWA.
Potential Reproduction Steps
Note: These steps are based on source code analysis as our tooling does not yet have the ability to run functional exploits.
- Install a PWA in Chrome on macOS.
- In the PWA, open a popup window using
let p = window.open(...). - Right-click the PWA’s Dock icon to display the window list.
- While the menu is open, execute
p.close()in the PWA. This causes the browser to send a Mojo message to the shim, which results in the destruction of theNativeWidgetNSWindowBridgeand the deallocation of the correspondingNativeWidgetMacNSWindowobject. - Reclaim the freed memory in the shim process (e.g., by setting
document.titleon remaining windows to trigger allocations that may occupy the freed object’s memory slot). - Select the stale popup window entry from the Dock menu.
AppShimApplicationwill attempt to dispatch the_selectWindow:action to the freed/reclaimed object.
Recommendation
Implement the same sendAction:to:from: override in AppShimApplication (located in chrome/app_shim/app_shim_application.mm) as exists in BrowserCrApplication (chrome/browser/chrome_browser_application_mac.mm) to validate that the target of a _selectWindow: action is a valid window in the application’s window list.
Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a
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.