Moderate severityOSV Advisory· Published Dec 17, 2025· Updated Dec 17, 2025
DoS in Calls plugin via malformed UTF-8 in WebSocket request
CVE-2025-12689
Description
Mattermost versions 11.0.x <= 11.0.4, 10.12.x <= 10.12.2, 10.11.x <= 10.11.6 fail to check WebSocket request field for proper UTF-8 format, which allows attacker to crash Calls plug-in via sending malformed request.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/mattermost/mattermost-plugin-callsGo | < 1.11.0 | 1.11.0 |
Affected products
1- Range: @mattermost/client@10.11.0, @mattermost/client@10.12.0, @mattermost/client@11.0.4, …
Patches
1f68b41980e12MM-66161 MM-66170 Improve validation of websocket request (#1092)
3 files changed · +136 −0
server/client_message.go+25 −0 modified@@ -39,3 +39,28 @@ func (m *clientMessage) ToJSON() ([]byte, error) { func (m *clientMessage) FromJSON(data []byte) error { return json.Unmarshal(data, &m) } + +var validClientMessageTypes = map[string]bool{ + clientMessageTypeJoin: true, + clientMessageTypeLeave: true, + clientMessageTypeReconnect: true, + clientMessageTypeSDP: true, + clientMessageTypeICE: true, + clientMessageTypeMute: true, + clientMessageTypeUnmute: true, + clientMessageTypeVoiceOn: true, + clientMessageTypeVoiceOff: true, + clientMessageTypeScreenOn: true, + clientMessageTypeScreenOff: true, + clientMessageTypeRaiseHand: true, + clientMessageTypeUnraiseHand: true, + clientMessageTypeReact: true, + clientMessageTypeCaption: true, + clientMessageTypeMetric: true, + clientMessageTypeCallState: true, + "ping": true, // Special case: standard ping message +} + +func isValidClientMessageType(msgType string) bool { + return validClientMessageTypes[msgType] +}
server/websocket.go+14 −0 modified@@ -10,6 +10,7 @@ import ( "strings" "sync/atomic" "time" + "unicode/utf8" "github.com/mattermost/mattermost-plugin-calls/server/batching" "github.com/mattermost/mattermost-plugin-calls/server/public" @@ -1089,9 +1090,22 @@ func (p *Plugin) handleCallStateRequest(channelID, userID, connID string) error } func (p *Plugin) WebSocketMessageHasBeenPosted(connID, userID string, req *model.WebSocketRequest) { + if !utf8.ValidString(req.Action) { + p.LogError("invalid UTF-8 in action") + return + } + if !strings.HasPrefix(req.Action, wsActionPrefix) { + return + } var msg clientMessage msg.Type = strings.TrimPrefix(req.Action, wsActionPrefix) + // Validate message type against known valid types + if !isValidClientMessageType(msg.Type) { + p.LogError("invalid message type", "type", msg.Type) + return + } + // This is the standard ping message handled by Mattermost server. Nothing to do here. if msg.Type == "ping" { return
server/websocket_test.go+97 −0 modified@@ -669,6 +669,103 @@ func TestPublishWebSocketEvent(t *testing.T) { }) } +func TestWebSocketMessageHasBeenPostedUTF8Validation(t *testing.T) { + mockAPI := &pluginMocks.MockAPI{} + + defer mockAPI.AssertExpectations(t) + + p := Plugin{ + MattermostPlugin: plugin.MattermostPlugin{ + API: mockAPI, + }, + } + + t.Run("invalid UTF-8 in action", func(_ *testing.T) { + // Create action with invalid UTF-8 bytes (0xFF, 0xFE) + malformedAction := wsActionPrefix + "join" + string([]byte{0xFF, 0xFE}) + + req := &model.WebSocketRequest{ + Action: malformedAction, + Data: map[string]interface{}{ + "channelID": model.NewId(), + }, + } + + mockAPI.On("LogError", "invalid UTF-8 in action", "origin", mock.AnythingOfType("string")).Once() + + p.WebSocketMessageHasBeenPosted(model.NewId(), model.NewId(), req) + }) + + t.Run("missing action prefix - returns early", func(t *testing.T) { + // Action without the correct prefix should be ignored + req := &model.WebSocketRequest{ + Action: "some_other_plugin_action", + Data: map[string]interface{}{ + "channelID": model.NewId(), + }, + } + + // Explicitly assert no API methods are called - proves early return + p.WebSocketMessageHasBeenPosted(model.NewId(), model.NewId(), req) + + mockAPI.AssertNotCalled(t, "LogError") + mockAPI.AssertNotCalled(t, "LogDebug") + mockAPI.AssertNotCalled(t, "LogInfo") + }) + + t.Run("invalid message type", func(_ *testing.T) { + // Action with correct prefix but unknown message type + req := &model.WebSocketRequest{ + Action: wsActionPrefix + "invalid_unknown_action", + Data: map[string]interface{}{}, + } + + mockAPI.On("LogError", "invalid message type", "origin", mock.AnythingOfType("string"), "type", "invalid_unknown_action").Once() + + p.WebSocketMessageHasBeenPosted(model.NewId(), model.NewId(), req) + }) + + t.Run("valid message type - ping", func(t *testing.T) { + // Ping is a valid message type that should be handled + req := &model.WebSocketRequest{ + Action: wsActionPrefix + "ping", + Data: map[string]interface{}{}, + } + + // Ping should return early after validation, no other API calls + p.WebSocketMessageHasBeenPosted(model.NewId(), model.NewId(), req) + + mockAPI.AssertNotCalled(t, "LogError") + }) + + t.Run("valid message types recognized", func(t *testing.T) { + // Test that isValidClientMessageType recognizes all defined message types + validTypes := []string{ + "join", "leave", "reconnect", "sdp", "ice", + "mute", "unmute", "voice_on", "voice_off", + "screen_on", "screen_off", "raise_hand", "unraise_hand", + "react", "caption", "metric", "call_state", "ping", + } + + for _, msgType := range validTypes { + if !isValidClientMessageType(msgType) { + t.Errorf("Valid message type %q not recognized by isValidClientMessageType", msgType) + } + } + + // Test that invalid types are rejected + invalidTypes := []string{ + "invalid", "unknown", "hack", "exploit", "", + } + + for _, msgType := range invalidTypes { + if isValidClientMessageType(msgType) { + t.Errorf("Invalid message type %q was incorrectly accepted by isValidClientMessageType", msgType) + } + } + }) +} + func TestHandleJoin(t *testing.T) { mockAPI := &pluginMocks.MockAPI{} mockMetrics := &serverMocks.MockMetrics{}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.