VYPR
Moderate severityOSV Advisory· Published Dec 17, 2025· Updated Dec 17, 2025

CSRF Allows Call Initiation and Message Delivery

CVE-2025-62190

Description

Mattermost versions 11.0.x <= 11.0.4, 10.12.x <= 10.12.2, 10.11.x <= 10.11.6 and Mattermost Calls versions <=1.10.0 fail to implement CSRF protection on the Calls widget page which allows an authenticated attacker to initiate calls and inject messages into channels or direct messages via a malicious webpage or crafted link

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/mattermost/mattermost-plugin-callsGo
< 1.10.01.10.0

Affected products

1

Patches

1
429cfaf2a301

[MM-64921] Prevent call start from CSRF request to widget.html (#1085)

https://github.com/mattermost/mattermost-plugin-callsChristopher PoileNov 3, 2025via ghsa
4 files changed · +41 2
  • e2e/page.ts+3 0 modified
    @@ -130,6 +130,9 @@ export default class PlaywrightDevPage {
             const resp = await this.page.request.get(`${baseURL}/api/v4/teams/name/${defaultTeam}/channels/name/${channelName}`);
             const channel = await resp.json();
     
    +        await this.page.setExtraHTTPHeaders({
    +            'X-Calls-E2E': 'true',
    +        });
             await this.page.goto(`${baseURL}/plugins/${pluginID}/standalone/widget.html?call_id=${channel.id}`);
             await expect(this.page.locator('#calls-widget')).toBeVisible();
             await expect(this.page.getByTestId('calls-widget-loading-overlay')).toBeHidden();
    
  • .github/workflows/e2e.yml+1 1 modified
    @@ -125,7 +125,7 @@ jobs:
           CONTAINER_RTCD: playwright_tests_rtcd
           CONTAINER_OFFLOADER: playwright_tests_offloader
           IMAGE_CALLS_OFFLOADER: mattermost/calls-offloader:v0.9.3
    -      IMAGE_CALLS_RECORDER: mattermost/calls-recorder:v0.8.6
    +      IMAGE_CALLS_RECORDER: mattermost/calls-recorder:v0.8.8
           IMAGE_CALLS_TRANSCRIBER: mattermost/calls-transcriber:v0.7.1
           IMAGE_SERVER: mattermostdevelopment/mattermost-enterprise-edition:master
           IMAGE_CURL: curlimages/curl:8.7.1
    
  • plugin.json+1 1 modified
    @@ -716,7 +716,7 @@
       "props": {
         "min_rtcd_version": "v0.17.0",
         "min_offloader_version": "v0.9.0",
    -    "calls_recorder_version": "v0.8.6",
    +    "calls_recorder_version": "v0.8.8",
         "calls_transcriber_version": "v0.7.1"
       }
     }
    
  • server/api.go+36 0 modified
    @@ -8,7 +8,9 @@ import (
     	"errors"
     	"fmt"
     	"net/http"
    +	"net/url"
     	"path/filepath"
    +	"strings"
     
     	"golang.org/x/time/rate"
     
    @@ -284,6 +286,40 @@ func (p *Plugin) handleDismissNotification(w http.ResponseWriter, r *http.Reques
     }
     
     func (p *Plugin) handleServeStandalone(w http.ResponseWriter, r *http.Request) {
    +	// Referrer-based CSRF protection
    +	referrer := r.Header.Get("Referer")
    +	userAgent := r.UserAgent()
    +
    +	// Allow desktop or recorder (which uses our custom recorder header), or E2E
    +	isDesktopApp := strings.Contains(userAgent, "Mattermost") && strings.Contains(userAgent, "Electron")
    +	hasRecorderHeader := r.Header.Get("X-Calls-Recorder") == "true"
    +	hasE2EHeader := r.Header.Get("X-Calls-E2E") == "true"
    +	needsReferrerCheck := !(isDesktopApp || hasRecorderHeader || hasE2EHeader)
    +	if needsReferrerCheck {
    +		if referrer != "" {
    +			// For web browsers, check referrer for CSRF protection
    +			referrerURL, err := url.Parse(referrer)
    +			if err != nil {
    +				p.LogWarn("Serve standalone, BLOCKED: Invalid referrer", "err", err.Error())
    +				http.Error(w, "Forbidden", http.StatusForbidden)
    +				return
    +			}
    +
    +			if referrerURL.Host != r.Host {
    +				p.LogWarn("Serve standalone, BLOCKED: Cross-origin referrer", "from", referrerURL.Host, "to", r.Host)
    +				http.Error(w, "Forbidden", http.StatusForbidden)
    +				return
    +			}
    +
    +			// Allow same-origin referrers
    +		} else {
    +			// No referrer - could be direct navigation (OK) or malicious site with referrer policy
    +			p.LogWarn("Serve standalone, BLOCKED: no referrer")
    +			http.Error(w, "Forbidden", http.StatusForbidden)
    +			return
    +		}
    +	}
    +
     	bundlePath, err := p.API.GetBundlePath()
     	if err != nil {
     		p.LogError(err.Error())
    

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

5

News mentions

0

No linked articles in our index yet.