From 8818c8c94530b05dc5e247390358619e05c329ce Mon Sep 17 00:00:00 2001 From: Vitali Zaidman Date: Thu, 26 Feb 2026 10:13:09 -0800 Subject: [PATCH 1/3] Add URL validation check to prevent crash Summary: Add defensive check to validate the WebSocket URL before attempting to connect. This prevents potential crashes when an invalid or nil URL is passed to the WebSocket module, which could cause XPC serialization failures deep in the network stack. The crash was observed in during XPC serialization when SocketRocket attempted to open a connection with invalid URL data. Differential Revision: [to be generated] D94375527 --- .../react-native/React/CoreModules/RCTWebSocketModule.mm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm index e29d76a76a23..2cc853c86d45 100644 --- a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm +++ b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm @@ -10,6 +10,7 @@ #import #import +#import #import #import #import @@ -66,6 +67,14 @@ - (void)invalidate connect : (NSURL *)URL protocols : (NSArray *)protocols options : (JS::NativeWebSocketModule::SpecConnectOptions &) options socketID : (double)socketID) { + if ((URL == nil) || URL.absoluteString.length == 0u) { + RCTAssert(NO, @"RCTWebSocketModule: Invalid WebSocket URL passed to connect"); + NSNumber *socketIDNumber = @(socketID); + NSDictionary *body = @{@"message" : @"Invalid WebSocket URL", @"id" : socketIDNumber}; + [self sendEventWithName:@"websocketFailed" body:body]; + return; + } + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; // We load cookies from sharedHTTPCookieStorage (shared with XHR and From 328981e372b907670116a647a0ca8e7e636c730f Mon Sep 17 00:00:00 2001 From: Vitali Zaidman Date: Thu, 26 Feb 2026 10:35:27 -0800 Subject: [PATCH 2/3] Add cookie URL validation check to prevent crash Summary: Add defensive check to validate components.URL before using it to load cookies. If NSURLComponents fails to parse the URL or returns nil for components.URL, this prevents passing nil to cookiesForURL which could cause issues in the network stack. Differential Revision: D94375528 --- .../react-native/React/CoreModules/RCTWebSocketModule.mm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm index 2cc853c86d45..5501e0ff8778 100644 --- a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm +++ b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm @@ -86,8 +86,12 @@ - (void)invalidate } // Load and set the cookie header. - NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:components.URL]; - request.allHTTPHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies]; + if (components != nil && components.URL != nil) { + NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:components.URL]; + request.allHTTPHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies]; + } else { + RCTLogError(@"RCTWebSocketModule: Invalid URL components - components or components.URL is nil"); + } // Load supplied headers if ([options.headers() isKindOfClass:NSDictionary.class]) { From 4ff1d2e7c428862de123abb40c68021fc3e2e818 Mon Sep 17 00:00:00 2001 From: Vitali Zaidman Date: Thu, 26 Feb 2026 11:20:08 -0800 Subject: [PATCH 3/3] Add headers validation check to prevent crash (#55749) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/55749 Add defensive checks when processing custom headers to ensure: 1. Header keys are valid NSString instances before using them 2. Header values are successfully converted before adding to the request This prevents potential crashes when invalid header data (non-string keys or values that fail conversion) is passed from JavaScript to the WebSocket module. Changelog: [Internal] Differential Revision: D94375533 --- .../React/CoreModules/RCTWebSocketModule.mm | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm index 5501e0ff8778..e82bde27dfd7 100644 --- a/packages/react-native/React/CoreModules/RCTWebSocketModule.mm +++ b/packages/react-native/React/CoreModules/RCTWebSocketModule.mm @@ -96,8 +96,38 @@ - (void)invalidate // Load supplied headers if ([options.headers() isKindOfClass:NSDictionary.class]) { NSDictionary *headers = (NSDictionary *)options.headers(); - [headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { - [request addValue:[RCTConvert NSString:value] forHTTPHeaderField:key]; + [headers enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + BOOL validKey = [key isKindOfClass:[NSString class]]; + BOOL validValue = [value isKindOfClass:[NSString class]]; + + if (!validKey && !validValue) { + RCTLogError( + @"RCTWebSocketModule: Invalid header key and value types. " + "Expected NSString for both, got key of type %@ and value of type %@.", + NSStringFromClass([key class]), + NSStringFromClass([value class])); + return; + } + + if (!validKey) { + RCTLogError( + @"RCTWebSocketModule: Invalid header key type for value '%@'. " + "Expected NSString, got %@.", + value, + NSStringFromClass([key class])); + return; + } + + if (!validValue) { + RCTLogError( + @"RCTWebSocketModule: Invalid header value type for key '%@'. " + "Expected NSString, got %@.", + key, + NSStringFromClass([value class])); + } + + NSString *headerValue = validValue ? [RCTConvert NSString:value] : @""; + [request addValue:headerValue forHTTPHeaderField:key]; }]; }