Skip to content

macOS: a secure TextInput crashes the app when it takes focus #3138

Open

Description

Description

A TextInput with secureTextEntry crashes the app on macOS as soon as it takes focus. AppKit's secure field editor (NSSecureTextView) requires its delegate to be an NSSecureTextField, and RCTUISecureTextField is not one: since #2895 it subclasses RCTUITextField (an NSTextField) and gets its secure behaviour from an NSSecureTextFieldCell. When the field becomes first responder, -[NSSecureTextView setDelegate:] throws.

Answering isKindOfClass: for NSSecureTextField gets past that, but isn't enough on its own: NSSecureTextView then sends its delegate the private -_shouldShowIndicators as it draws, and the unrecognised selector throws from -[NSSecureTextView drawRect:]. We hit that second crash too, a few minutes into using the field. As far as I can see from AppKit, -_shouldShowIndicators is the only NSSecureTextField-only message NSSecureTextView sends its delegate.

Seen on macOS 26.6.2 with an app built by Xcode 27.1; not checked on earlier macOS.

Steps to reproduce

  1. In RNTester, put a secure field in the Playground (packages/rn-tester/js/examples/Playground/RNTesterPlayground.js):
    <TextInput secureTextEntry={true} placeholder="Password" style={{borderWidth: 1, height: 30}} />
  2. Run RNTester-macOS, open the Playground tab, and click into the field (or call focus() on it).

The app terminates with the exception below.

React Native Version

0.83.10, with react-native-macos 0.83.0. Also on main (8941740).

Affected Platforms

Runtime - MacOS

Output of npx @react-native-community/cli info

OS: macOS 26.6.2 (25G83), Apple M3
Xcode 27.1 (27A9275), macOS SDK 27.0
Node 24.19.0, CocoaPods 1.17.0
react-native 0.83.10, react-native-macos 0.83.0, new architecture

Stacktrace or Logs

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSSecureTextFieldCell is not secure because the secure field editor's delegate must be an NSSecureTextField! Delegate is: <RCTUISecureTextField: 0x...>'
*** First throw call stack:
(
	0   CoreFoundation               __exceptionPreprocess + 164
	1   libobjc.A.dylib              objc_exception_throw + 88
	2   Foundation                   -[NSCalendarDate initWithCoder:]
	3   AppKit                       -[NSSecureTextView setDelegate:] + 496
	4   AppKit                       _NSEditTextCellWithOptions + 1636
	5   AppKit                       -[NSCell _selectOrEdit:inView:target:editor:event:start:end:] + 204
	6   AppKit                       -[NSTextFieldCell _selectOrEdit:inView:target:editor:event:start:end:] + 280
	7   AppKit                       -[NSCell selectWithFrame:inView:editor:delegate:start:length:] + 56
	8   AppKit                       -[NSSecureTextFieldCell selectWithFrame:inView:editor:delegate:start:length:] + 228
	9   RNTester-macOS.debug.dylib   -[RCTUISecureTextFieldCell selectWithFrame:inView:editor:delegate:start:length:] + 300
	10  AppKit                       +[NSAppearance _performWithCurrentAppearance:usingBlock:] + 72
	11  AppKit                       -[NSTextField selectText:] + 208
	12  AppKit                       -[NSTextField becomeFirstResponder] + 172
	13  RNTester-macOS.debug.dylib   -[RCTUITextField becomeFirstResponder] + 60
	14  AppKit                       -[NSWindow _realMakeFirstResponder:] + 560
	15  RNTester-macOS.debug.dylib   -[RCTTextInputComponentView focus] + 292
	16  RNTester-macOS.debug.dylib   RCTTextInputHandleCommand + 288
	17  RNTester-macOS.debug.dylib   -[RCTTextInputComponentView handleCommand:args:] + 76

The second crash, with isKindOfClass: answered:

	0   CoreFoundation   __exceptionPreprocess + 176
	1   libobjc.A.dylib  objc_exception_throw + 88
	2   CoreFoundation   -[NSObject(NSObject) __retain_OA] + 0
	3   CoreFoundation   ___forwarding___ + 1480
	4   CoreFoundation   _CF_forwarding_prep_0 + 96
	5   AppKit           -[NSSecureTextView _shouldShowIndicators] + 64
	6   AppKit           -[NSSecureTextView drawRect:] + 320
	...
	11  AppKit           _NSViewDrawRect + 132

Reproducer

The Playground change in step 1, against main (8941740). A PR with a fix follows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions