Overview

Critical
Severity
8.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input Accessibility
DescriptionInsufficient validation of untrusted input Accessibility
ComponentChromium
Sub-componentA11y
Bug ClassInput Validation
Action tierwatch — ub-class only — no demonstrated corruption path
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker517332006
Fix commitb67efd3a537b (chromium/src) +2/-0
CWECWE-20 (Improper input validation)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-05-28 (per vendor advisory)
Fix landed2026-06-04 (public git)
Disclosed2026-06-11
Patch gap7 days — fix public in source before the advisory

Background

`NOTREACHED()`
A Chromium control-flow assertion that marks a code path the developer believes can never execute, aborting (in most builds) and hinting to the compiler that no code follows.
`AXPlatformNodeCocoa`
The macOS Objective-C class that exposes Chromium’s accessibility tree nodes to the platform via the Cocoa NSAccessibility API, in ui/accessibility/platform/ax_platform_node_cocoa.mm.
`ax::mojom` enums
Accessibility attribute enumerations (e.g. ax::mojom::InvalidState, ax::mojom::HasPopup) carried over mojom IPC that describe node state and can, in principle, hold an integer outside the declared enumerators.
Exhaustive `switch`
A switch covering every declared enumerator with no default: case, which falls off the end (returning an indeterminate value from a non-void method) if the scrutinee is out of range.

Root Cause Analysis

The two accessibility accessor methods edited in ax_platform_node_cocoa.mm each contain a switch over an ax::mojom enum with one return per enumerator and no trailing return or default: after the closing brace, as shown by the hunks ending on return @"true";/} and return @"dialog";/}. If the enum value supplied to such a method is an out-of-range integer, control reaches the end of the non-void Objective-C method without executing any return, yielding an indeterminate object-pointer result — the exact “out-of-range integers” condition the commit message calls out. The invariant being restored is that the switch is truly total: every reachable value produces a defined return.

The fix adds NOTREACHED() immediately after each switch (the two added lines), so an unexpected value terminates deterministically instead of falling through, and the compiler is told the post-switch path is dead, which also silences the Fortify out-of-range reports the commit message references. Because both enumerators shown (ax::mojom::InvalidState::kTrue, ax::mojom::HasPopup::kDialog) are handled, the change alters behavior only on the previously-undefined out-of-range path.

Key insight
The core mistake is treating an untrusted ax::mojom enum as guaranteed in-range and relying on an exhaustive switch with no fallthrough handling, so an out-of-range value produced an indeterminate return; adding NOTREACHED() converts that silent, undefined fall-through into a deterministic, compiler-recognized dead path.

Attack Path

  1. Supply an out-of-range enum value Deliver an accessibility node whose InvalidState or HasPopup attribute carries an integer outside the declared enumerators, reaching the affected methods over the accessibility/mojom surface the advisory classes as “insufficient validation of untrusted input” (inferred that the value can be attacker-influenced; the diff shows only the consuming switch).
  2. Fall off the exhaustive switch Because neither switch has a default: or trailing return, the out-of-range value matches no case and control reaches the end of the non-void method with no return executed.
  3. Return an indeterminate object pointer The method returns whatever indeterminate value occupies the return register/stack slot, which downstream Cocoa accessibility code may consume as an NSString*/NSNumber* (inferred; the diff does not show the consumer or any dereference).
  4. Potential further escalation Any memory-safety consequence beyond the indeterminate return (e.g. type confusion or invalid pointer use in the a11y consumer) is not demonstrated by the diff and is (inferred); the patch itself only hardens the fall-through, and the change is described as preventing Fortify reports.

Impact Assessment

An attacker who can influence an accessibility node’s InvalidState/HasPopup enum value could drive one of these methods off the end of an exhaustive switch, causing it to return an indeterminate object pointer in the browser/renderer accessibility path (the affected code is macOS AXPlatformNodeCocoa). The concrete precondition is delivering an out-of-range enum over the accessibility surface; any exploitation beyond undefined-value return — memory corruption, information disclosure, or code execution — is (inferred) and not established by the diff. The vendor advisory rates this critical severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.3. The commit frames the change as hardening that also prevents Fortify out-of-range reports.

Files Changed

  • ui/accessibility/platform/ax_platform_node_cocoa.mm

Audit Directions

  • Exhaustive switches with no fallthrough
    Look for switch statements over ax::mojom (and other IPC-sourced) enums in non-void functions that lack a default: or trailing return, since an out-of-range value falls off the end into undefined behavior.
  • Untrusted enums crossing mojom
    Audit accessibility and other mojom-deserialized enum values that are used directly as switch scrutinees without range validation, where a malformed integer can bypass all cases.
  • Indeterminate-return object accessors
    Review Objective-C/C++ accessors that return object pointers from a terminal switch, where a missing NOTREACHED()/default: lets the method return an uninitialized or indeterminate pointer that downstream code dereferences.
From b67efd3a537b800df6fc49d48089b241b7d6c843 Mon Sep 17 00:00:00 2001
From: Carlos Barrera <carlosbarrera@google.com>
Date: Thu, 04 Jun 2026 10:01:08 -0700
Subject: [PATCH] [a11y] Add NOTREACHED() to exhaustive switches in AXPlatformNodeCocoa

This change adds NOTREACHED() to the AXInvalid and AXPopupValue methods
in AXPlatformNodeCocoa. These methods use exhaustive switches over
enums, and adding NOTREACHED() prevents Fortify reports regarding
out-of-range integers and ensures the compiler recognizes all paths
are covered.

AX-Relnotes: n/a.
Bug: 517332006
Change-Id: Ie2c780582f6b40b84e81f422b7ebff32c1387b16
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7896760
Reviewed-by: David Tseng <dtseng@chromium.org>
Commit-Queue: Carlos Marcelo Barrera Nolasco <carlosbarrera@google.com>
Cr-Commit-Position: refs/heads/main@{#1641747}
---

diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm
index 58b407e..375ff742 100644
--- a/ui/accessibility/platform/ax_platform_node_cocoa.mm
+++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -2219,6 +2219,7 @@
     case ax::mojom::InvalidState::kTrue:
       return @"true";
   }
+  NOTREACHED();
 }
 
 - (NSNumber*)AXIsMultiSelectable {
@@ -2281,6 +2282,7 @@
     case ax::mojom::HasPopup::kDialog:
       return @"dialog";
   }
+  NOTREACHED();
 }
 
 - (NSNumber*)AXRequired {
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Browser-Process UB in -[AXPlatformNodeCocoa AXInvalid] and AXPopupValue on macOS

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: A compromised renderer can supply out-of-range integers for accessibility enum attributes due to a lack of Mojo validation. When accessed via macOS accessibility selectors, this can cause control flow to fall off the end of non-void Objective-C methods. This leads to undefined behavior and potential code execution in the unsandboxed browser process.

Affected files:

  • ui/accessibility/platform/ax_platform_node_cocoa.mm
  • ui/accessibility/mojom/ax_node_data_mojom_traits.cc
  • ui/accessibility/ax_node_data.cc

Estimated timestamp from git blame: 2021-11-09

Technical Analysis

1. Unvalidated Mojo Deserialization of Enum Attributes

In ui/accessibility/mojom/ax_node_data_mojom_traits.cc, the int_attributes map is deserialized directly without verifying that the integers correspond to valid enum ranges:

if (!data.ReadIntAttributes(&out->int_attributes.container())) {
  return false;
}

Because attributes like ax::mojom::InvalidState are defined as enums with limited valid values (e.g., kNone = 0, kFalse = 1, kTrue = 2), a compromised renderer can pass arbitrary out-of-range values (such as 3 or 0x10000000) for the ax::mojom::IntAttribute::kInvalidState key.

2. Enum Casting in the Browser Process

In ui/accessibility/ax_node_data.cc (line 591), AXNodeData::GetInvalidState() performs a static cast on the unvalidated attribute retrieved from the map:

ax::mojom::InvalidState AXNodeData::GetInvalidState() const {
  return static_cast<ax::mojom::InvalidState>(
      GetIntAttribute(ax::mojom::IntAttribute::kInvalidState));
}

3. Undefined Behavior in -[AXPlatformNodeCocoa AXInvalid]

In ui/accessibility/platform/ax_platform_node_cocoa.mm (line 2212), the macOS-specific selector switches on this state:

- (NSString*)AXInvalid {
  if (![self instanceActive])
    return nil;
  switch (_node->GetData().GetInvalidState()) {
    case ax::mojom::InvalidState::kNone:
    case ax::mojom::InvalidState::kFalse:
      return @"false";
    case ax::mojom::InvalidState::kTrue:
      return @"true";
  }
}

Because this switch is exhaustive relative to the enum definition, Clang assumes that all execution paths are covered and does not issue a -Wreturn-type warning or compilation error. However, at runtime, an out-of-range value (like 3) causes control flow to fall off the end of this non-void method.

In compiled Objective-C++ binaries, falling off a non-void method is undefined behavior. The compiler typically omits setting the return register (rax/x0), leaving a stale or garbage pointer. Since the caller (AppKit or VoiceOver dispatch) expects a valid NSString* return value, treating this garbage value as an object pointer and passing it to ARC reference management (e.g., objc_retainAutoreleasedReturnValue) or invoking selectors on it can lead to control flow hijack and potential RCE in the unsandboxed browser process.

4. Sibling Vulnerability: -[AXPlatformNodeCocoa AXPopupValue]

The exact same vulnerable pattern is present in -[AXPlatformNodeCocoa AXPopupValue] (line 2264) in the same file:

- (NSString*)AXPopupValue {
  if (![self instanceActive])
    return nil;
  int hasPopup = _node->GetIntAttribute(ax::mojom::IntAttribute::kHasPopup);
  switch (static_cast<ax::mojom::HasPopup>(hasPopup)) {
    case ax::mojom::HasPopup::kFalse:
      return @"false";
    case ax::mojom::HasPopup::kTrue:
      return @"true";
    case ax::mojom::HasPopup::kMenu:
      return @"menu";
    case ax::mojom::HasPopup::kListbox:
      return @"listbox";
    case ax::mojom::HasPopup::kTree:
      return @"tree";
    case ax::mojom::HasPopup::kGrid:
      return @"grid";
    case ax::mojom::HasPopup::kDialog:
      return @"dialog";
  }
}

This similarly falls off the end of the non-void method when an out-of-range integer is supplied for kHasPopup.


Potential Steps to Trigger (Hypothetical)

Note: These are potential steps based on source code analysis; our tooling has not run any code to verify execution.

  1. From a compromised Renderer process, access the blink::mojom::RenderAccessibilityHost interface.
  2. Construct an AXUpdatesAndEvents payload where an AXNodeData’s int_attributes map contains the key ax::mojom::IntAttribute::kInvalidState mapped to an out-of-range value (e.g., 3).
  3. Invoke the HandleAXEvents Mojo method with this payload.
  4. On macOS, trigger an accessibility query from a client (e.g., VoiceOver) that targets the modified node’s AXInvalid attribute.
  5. Observe a browser process crash or control flow hijack when AppKit attempts to process the returned garbage pointer.

Suggested Remediation

To safely handle unexpected enum values and prevent undefined behavior, do one of the following:

  1. Add a trailing return / default case: Ensure that all non-void platform methods have a fallback return value or a terminating NOTREACHED() if an invalid value is encountered:
- (NSString*)AXInvalid {
  if (![self instanceActive])
    return nil;
  switch (_node->GetData().GetInvalidState()) {
    case ax::mojom::InvalidState::kNone:
    case ax::mojom::InvalidState::kFalse:
      return @"false";
    case ax::mojom::InvalidState::kTrue:
      return @"true";
  }
  return nil; // Fallback to prevent falling off the end
}

Apply a similar fix to AXPopupValue and other sibling methods in ax_platform_node_cocoa.mm.

  1. Validate during Mojo Deserialization: Update ui/accessibility/mojom/ax_node_data_mojom_traits.cc to sanitize enum-typed integer values upon receipt, rejecting payloads that contain invalid out-of-range values.

Evaluated with Chrome root at commit: b1520ef4a76878853a31f0943b565e42060edec8


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.

View on issue tracker