Summary
WebSocketFrameDecoder used Swift's trapping Int(_:) initializer to convert the 8-byte extended payload length field of a WebSocket frame (RFC 6455 §5.2). Any 64-bit length value with the most-significant bit set (≥ 0x8000_0000_0000_0000) caused a fatal runtime trap and terminated the process. The trap fired before maxFrameSize validation, so no configuration could mitigate it, and ByteToMessageDecoder cannot catch a runtime trap.
Impact
An unauthenticated remote peer can crash any NIOWebSocket-based server (including Vapor and Hummingbird) with a single 11-byte frame sent after a completed WebSocket handshake, dropping all active connections until the process restarts.
Proof of Concept
81 7F 80 00 00 00 00 00 00 00 00
Fix
Fixed in #3603: the decoder now uses Int(exactly:) and throws NIOWebSocketError.invalidFrameLength for out-of-range lengths instead of trapping.
Found & Fixed by @g0w6y
Summary
WebSocketFrameDecoderused Swift's trappingInt(_:)initializer to convert the 8-byte extended payload length field of a WebSocket frame (RFC 6455 §5.2). Any 64-bit length value with the most-significant bit set (≥0x8000_0000_0000_0000) caused a fatal runtime trap and terminated the process. The trap fired beforemaxFrameSizevalidation, so no configuration could mitigate it, andByteToMessageDecodercannot catch a runtime trap.Impact
An unauthenticated remote peer can crash any
NIOWebSocket-based server (including Vapor and Hummingbird) with a single 11-byte frame sent after a completed WebSocket handshake, dropping all active connections until the process restarts.Proof of Concept
Fix
Fixed in #3603: the decoder now uses
Int(exactly:)and throwsNIOWebSocketError.invalidFrameLengthfor out-of-range lengths instead of trapping.Found & Fixed by @g0w6y