From 78649f9fee742da75ec4c78fc21eb2d505ef5ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C4=B0brahim=20Aksoy?= Date: Thu, 22 Jan 2026 13:23:12 +0300 Subject: [PATCH 1/2] Deny unmasked frame receive on server --- .../src/Resources/Strings.resx | 3 +++ .../src/System/Net/WebSockets/ManagedWebSocket.cs | 5 +++++ .../System.Net.WebSockets/tests/WebSocketTests.cs | 15 +++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/libraries/System.Net.WebSockets/src/Resources/Strings.resx b/src/libraries/System.Net.WebSockets/src/Resources/Strings.resx index a57e81b239a92c..a6033ed9cf8313 100644 --- a/src/libraries/System.Net.WebSockets/src/Resources/Strings.resx +++ b/src/libraries/System.Net.WebSockets/src/Resources/Strings.resx @@ -117,6 +117,9 @@ The WebSocket server sent a masked frame. + + The WebSocket client sent an unmasked frame. + The WebSocket received a continuation frame from a previous final message. diff --git a/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs index 8a26a4c29e2eb0..1e80e82bdde01a 100644 --- a/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs +++ b/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs @@ -1366,6 +1366,11 @@ private async ValueTask CloseWithReceiveErrorAndThrowAsync( // Consume the mask bytes ConsumeFromBuffer(4); } + else if (_isServer) + { + resultHeader = default; + return SR.net_Websockets_ServerReceivedUnmaskedFrame; + } // Do basic validation of the header switch (header.Opcode) diff --git a/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs b/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs index 73e84998a94197..d75d97706e40d3 100644 --- a/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs +++ b/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs @@ -182,6 +182,21 @@ public async Task ThrowWhenContinuationWithDifferentCompressionFlags() client.SendAsync(Memory.Empty, WebSocketMessageType.Binary, WebSocketMessageFlags.EndOfMessage, default)); } + [Fact] + public async Task ReceiveAsync_ServerUnmaskedFrame_ThrowsWebSocketException() + { + byte[] frame = { 0x81, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F }; + using var stream = new MemoryStream(); + stream.Write(frame, 0, frame.Length); + stream.Position = 0; + using WebSocket websocket = WebSocket.CreateFromStream(stream, new WebSocketCreationOptions { IsServer = true }); + + WebSocketException exception = await Assert.ThrowsAsync(() => + websocket.ReceiveAsync(new byte[5], CancellationToken.None)); + Assert.Equal(SR.net_Websockets_ServerReceivedUnmaskedFrame, exception.Message); + Assert.Equal(WebSocketState.Aborted, websocket.State); + } + [Fact] public async Task ReceiveAsync_WhenDisposedInParallel_DoesNotGetStuck() { From b91d13d24a45303cfb52621234f7939e3f9a014e Mon Sep 17 00:00:00 2001 From: Ahmet Ibrahim Aksoy Date: Thu, 22 Jan 2026 13:39:05 +0300 Subject: [PATCH 2/2] Update src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs b/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs index d75d97706e40d3..41c7fe341d266d 100644 --- a/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs +++ b/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs @@ -190,7 +190,6 @@ public async Task ReceiveAsync_ServerUnmaskedFrame_ThrowsWebSocketException() stream.Write(frame, 0, frame.Length); stream.Position = 0; using WebSocket websocket = WebSocket.CreateFromStream(stream, new WebSocketCreationOptions { IsServer = true }); - WebSocketException exception = await Assert.ThrowsAsync(() => websocket.ReceiveAsync(new byte[5], CancellationToken.None)); Assert.Equal(SR.net_Websockets_ServerReceivedUnmaskedFrame, exception.Message);