diff --git a/src/libraries/System.Net.WebSockets/src/Resources/Strings.resx b/src/libraries/System.Net.WebSockets/src/Resources/Strings.resx
index 3ddd42906a160c..501137ffe613ff 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 4e3a261e1ecb77..553a254c2770d4 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
@@ -1349,6 +1349,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..41c7fe341d266d 100644
--- a/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs
+++ b/src/libraries/System.Net.WebSockets/tests/WebSocketTests.cs
@@ -182,6 +182,20 @@ 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()
{