CVE-2026-9885
Overview
Background
- `WebMenuRunner`
- the macOS Objective-C helper in the Cocoa remote process that builds and runs an
NSMenufor HTML<select>popup menus, taking font size and item data supplied from the renderer. - `_fontSize`
- the instance field on
WebMenuRunnerthat stores the font size used to render popup-menu items. - `kMaximumAllowedFontSize`
- a Blink constant (
10000.0f) capping font sizes “to prevent unreasonable font sizes from causing crashes on some platforms”. - Renderer-to-browser trust boundary
- values computed in the (sandboxed, potentially compromised) renderer must be re-validated by browser/privileged-process code rather than trusted blindly.
Root Cause Analysis
In content/app_shim_remote_cocoa/web_menu_runner_mac.mm, the WebMenuRunner initializer stored the incoming fontSize directly (_fontSize = fontSize;) with no bound, trusting that Blink in the renderer had already capped it to kMaximumAllowedFontSize. As the commit message states, “Blink caps font sizes on the renderer side, but browser-side code should not rely on that”: a compromised or misbehaving renderer can send an arbitrarily large (or otherwise unreasonable) font size across the IPC boundary. An oversized font size reaching the macOS menu-rendering path can cause crashes on some platforms, which is why Blink caps it in the first place.
The fix clamps the browser-side value with _fontSize = std::min(fontSize, 10'000.0);, re-establishing the cap independently of the renderer, and adds matched LINT.IfChange/LINT.ThenChange markers tying the browser cap to the Blink constant kMaximumAllowedFontSize. The change to third_party/blink/renderer/core/style/computed_style_constants.h only refreshes the comment and adds the LINT linkage; the constant value (10000.0f) is unchanged, so the behavioral fix is entirely the std::min clamp in the browser process.
std::min(fontSize, 10'000.0) so a malicious renderer can no longer deliver an uncapped value.Attack Path
- Control the renderer
An attacker who has compromised a renderer (or can otherwise forge the IPC message) prepares a popup-menu/
<select>payload destined for the macOSWebMenuRunner. - Send an uncapped font size
Because the renderer’s Blink-side cap is bypassed by the compromised process, a font size far above
kMaximumAllowedFontSizeis sent across the trust boundary. - Store the unvalidated value
Pre-patch, the
WebMenuRunnerinitializer assigned the oversizedfontSizestraight into_fontSizewith no clamp. - Crash during menu rendering
The unreasonable font size flows into the macOS menu/
NSMenurendering path and causes a crash on affected platforms (the specific downstream corruption, if any, is not shown by the diff and is(inferred)).
Impact Assessment
UI. The precondition is the macOS platform plus a renderer able to emit an out-of-range font size (a compromised renderer being the realistic path, since benign Blink already caps it). The diff shows only the missing bound and the crash risk it created; any escalation beyond a crash is (inferred), and the advisory does not report in-the-wild exploitation.Changed Functions
| Function | Change | Notes |
|---|---|---|
forcontent/app_shim_remote_cocoa/web_menu_runner_mac.mm |
modified |
Files Changed
content/app_shim_remote_cocoa/web_menu_runner_mac.mmthird_party/blink/renderer/core/style/computed_style_constants.h
Audit Directions
- Renderer-enforced limits relied on downstreamHunt for browser/privileged-process code that consumes sizes, counts, offsets, or lengths with a comment or assumption that “the renderer already validated this”; each such value needs an independent browser-side bound.
- Cocoa/remote-cocoa IPC inputsReview
content/app_shim_remote_cocoaand similar Cocoa bridges where renderer-originated geometry and typography parameters reach native UI toolkits that may crash or misbehave on extreme inputs. - Paired constants without linkageLook for duplicated limit constants across process boundaries that lack
LINT.IfChange/LINT.ThenChange(or equivalent) coupling, since one side can silently drift and leave a gap.
Patch
From 44241f776394c53f5f373e8a71930cace1619cf2 Mon Sep 17 00:00:00 2001 From: Avi Drissman <[email protected]> Date: Mon, 04 May 2026 08:54:35 -0700 Subject: [PATCH] Cap font sizes for popup menus on Mac Blink caps font sizes on the renderer side, but browser-side code should not rely on that. Cap the font sizes on the browser side for popup menus. Fixed: 508452241 Link: https://chromium-review.googlesource.com/id/Ibc50186dff0979ae55b6f39e594460686a6a6964 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7806727 Commit-Queue: Avi Drissman <[email protected]> Reviewed-by: Mark Mentovai <[email protected]> Reviewed-by: Daniil Sakhapov <[email protected]> Cr-Commit-Position: refs/heads/main@{#1624714} --- diff --git a/content/app_shim_remote_cocoa/web_menu_runner_mac.mm b/content/app_shim_remote_cocoa/web_menu_runner_mac.mm index 0a7029b..053c47ff 100644 --- a/content/app_shim_remote_cocoa/web_menu_runner_mac.mm +++ b/content/app_shim_remote_cocoa/web_menu_runner_mac.mm @@ -50,7 +50,12 @@ if ((self = [super init])) { _menu = [[NSMenu alloc] initWithTitle:@""]; _menu.autoenablesItems = NO; - _fontSize = fontSize; + // LINT.IfChange(fontSize) + // Blink caps font sizes to 10,000 but browser process code can't rely on + // the renderer to behave correctly. + // https://crbug.com/508452241 + _fontSize = std::min(fontSize, 10'000.0); + // LINT.ThenChange(//third_party/blink/renderer/core/style/computed_style_constants.h:kMaximumAllowedFontSize) _rightAligned = rightAligned; for (const auto& item : items) { [self addItem:item]; diff --git a/third_party/blink/renderer/core/style/computed_style_constants.h b/third_party/blink/renderer/core/style/computed_style_constants.h index 4ad7dc5..0884520 100644 --- a/third_party/blink/renderer/core/style/computed_style_constants.h +++ b/third_party/blink/renderer/core/style/computed_style_constants.h @@ -475,9 +475,11 @@ kStretch }; -// Reasonable maximum to prevent insane font sizes from causing crashes on some +// LINT.IfChange(kMaximumAllowedFontSize) +// A maximum to prevent unreasonable font sizes from causing crashes on some // platforms (such as Windows). static const float kMaximumAllowedFontSize = 10000.0f; +// LINT.ThenChange(//content/app_shim_remote_cocoa/web_menu_runner_mac.mm:fontSize) enum class CSSBoxType : unsigned { kMissing,
Original Bug Report
Potential Heap Buffer Overflow in Mac WebMenuRunner via unvalidated item_font_size IPC
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 without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A compromised renderer can send a maliciously large item_font_size via the ShowPopupMenu IPC to the browser process. This unvalidated value is passed to macOS text rendering APIs, which may trigger an integer overflow during buffer allocation. This can result in a heap buffer overflow in the unsandboxed browser or App Shim process.
Affected files:
content/app_shim_remote_cocoa/web_menu_runner_mac.mmcontent/app_shim_remote_cocoa/render_widget_host_ns_view_bridge.mmcontent/browser/renderer_host/popup_menu_helper_mac.mmcontent/common/render_widget_host_ns_view.mojom
Estimated timestamp from git blame: 2024-02-09
Description
A potential heap buffer overflow exists in the macOS implementation of popup menus. The issue occurs because the font_size parameter passed from the renderer process via the blink.mojom.LocalFrameHost.ShowPopupMenu IPC is not validated or clamped by the browser process.
While Blink internally caps font sizes (e.g., to 10,000) during style resolution, a compromised renderer can bypass Blink and send an arbitrarily large double value (e.g., 1e30) directly over the Mojo IPC.
The browser process (RenderFrameHostImpl::ShowPopupMenu) receives this value and passes it unmodified through the PopupMenuHelper to the Remote Cocoa process via the RenderWidgetHostNSView::DisplayPopupMenu IPC. In content/app_shim_remote_cocoa/web_menu_runner_mac.mm, the unsanitized value is passed directly to the native macOS API:
attrs[NSFontAttributeName] = [NSFont menuFontOfSize:_fontSize];
When macOS AppKit and CoreGraphics prepare the menu for display, they compute the dimensions of the text to calculate the required backing store memory buffer (width * height * bytes_per_pixel). An astronomically large font size can cause this calculation to overflow the 64-bit integer limit, wrapping around to a small positive value. The system then allocates an undersized buffer. When CoreGraphics attempts to rasterize the massive glyphs into this small buffer, it results in an out-of-bounds write (Heap Buffer Overflow).
Because this UI rendering occurs in the unsandboxed browser process or App Shim process, memory corruption here can be leveraged to achieve a full sandbox escape and arbitrary code execution.
Potential Steps to Reproduce
Note: These are suggested steps for exploitation, as our tooling agent does not currently have the ability to run code to produce a working proof-of-concept.
- An attacker compromises the renderer process (e.g., via a V8 vulnerability).
- The compromised renderer connects to the
blink.mojom.LocalFrameHostMojo interface in the browser process. - The attacker calls the
ShowPopupMenumethod, providing aPopupMenuClient, bounds, and setting thefont_sizeparameter to an extreme value like1e30. - The browser process passes the value to the macOS App Shim process.
WebMenuRunnerinvokes[NSFont menuFontOfSize:1e30], triggering the OS-level integer overflow during menu rasterization and causing a heap buffer overflow.
Suggested Fix
Clamp the font_size parameter in RenderFrameHostImpl::ShowPopupMenu (in content/browser/renderer_host/render_frame_host_impl.cc) to a safe maximum before it is used or passed to platform-specific UI code. A maximum of 10000.0 would match Blink’s internal kMaximumAllowedFontSize and prevent malicious values from reaching the OS APIs.
Evaluated with Chrome root at commit: cc901875d53bf4e4fe0e01f02843871da4106e70
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.