VYPR
Low severityNVD Advisory· Published Jul 18, 2025· Updated Jul 18, 2025

Invite token is used as part of the secure communication

CVE-2025-6227

Description

Mattermost versions 10.5.x <= 10.5.7, 9.11.x <= 9.11.16 fail to negotiate a new token when accepting the invite which allows a user that intercepts both invite and password to send synchronization payloads to the server that originally created the invite via the REST API.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/mattermost/mattermost-serverGo
>= 10.5.0, < 10.5.810.5.8
github.com/mattermost/mattermost-serverGo
>= 9.11.0, < 9.11.179.11.17
github.com/mattermost/mattermost/server/v8Go
< 8.0.0-20250612074655-8f8612c637838.0.0-20250612074655-8f8612c63783

Affected products

1

Patches

1
fbf105f6ef8f

Improves the invite mechanism for remote clusters (#31025)

https://github.com/mattermost/mattermostMiguel de la CruzMay 27, 2025via ghsa
5 files changed · +36 11
  • server/channels/app/remote_cluster.go+1 0 modified
    @@ -202,6 +202,7 @@ func (a *App) CreateRemoteClusterInvite(remoteId, siteURL, token, password strin
     		RemoteId: remoteId,
     		SiteURL:  siteURL,
     		Token:    token,
    +		Version:  2,
     	}
     
     	if err := invite.IsValid(); err != nil {
    
  • server/platform/services/remotecluster/invitation.go+19 4 modified
    @@ -13,13 +13,21 @@ import (
     
     // AcceptInvitation is called when accepting an invitation to connect with a remote cluster.
     func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name string, displayName string, creatorId string, siteURL string, defaultTeamId string) (*model.RemoteCluster, error) {
    +	// Generate new token for RemoteToken only if invite version is 2 or greater
    +	var remoteToken string
    +	if invite.Version >= 2 {
    +		remoteToken = model.NewId() // Generate new token for v2+ protocol
    +	} else {
    +		remoteToken = invite.Token // Use the token from the invite for backwards compatibility
    +	}
    +
     	rc := &model.RemoteCluster{
     		RemoteId:      invite.RemoteId,
     		Name:          name,
     		DisplayName:   displayName,
     		DefaultTeamId: defaultTeamId,
     		Token:         model.NewId(),
    -		RemoteToken:   invite.Token,
    +		RemoteToken:   remoteToken,
     		SiteURL:       invite.SiteURL,
     		CreatorId:     creatorId,
     	}
    @@ -37,6 +45,11 @@ func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name str
     
     	url := fmt.Sprintf("%s/%s", rcSaved.SiteURL, ConfirmInviteURL)
     
    +	// for the invite confirm message, we need to use the token that
    +	// the originating server sent in the invite instead of the one
    +	// we're storing as a refresh
    +	rc.RemoteToken = invite.Token
    +
     	resp, err := rcs.sendFrameToRemote(PingTimeout, rc, frame, url)
     	if err != nil {
     		rcs.server.GetStore().RemoteCluster().Delete(rcSaved.RemoteId)
    @@ -63,9 +76,11 @@ func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name str
     
     func makeConfirmFrame(rc *model.RemoteCluster, siteURL string) (*model.RemoteClusterFrame, error) {
     	confirm := model.RemoteClusterInvite{
    -		RemoteId: rc.RemoteId,
    -		SiteURL:  siteURL,
    -		Token:    rc.Token,
    +		RemoteId:       rc.RemoteId,
    +		SiteURL:        siteURL,
    +		Token:          rc.Token,
    +		RefreshedToken: rc.RemoteToken,
    +		Version:        2,
     	}
     	confirmRaw, err := json.Marshal(confirm)
     	if err != nil {
    
  • server/platform/services/remotecluster/recv.go+5 0 modified
    @@ -69,6 +69,11 @@ func (rcs *Service) ReceiveInviteConfirmation(confirm model.RemoteClusterInvite)
     	rc.SiteURL = confirm.SiteURL
     	rc.RemoteToken = confirm.Token
     
    +	// If the accepting cluster sent a RefreshedToken (its RemoteToken), set it as our Token
    +	if confirm.Version >= 2 && confirm.RefreshedToken != "" {
    +		rc.Token = confirm.RefreshedToken
    +	}
    +
     	rcUpdated, err := store.Update(rc)
     	if err != nil {
     		return nil, fmt.Errorf("cannot apply invite confirmation for remote %s: %w", confirm.RemoteId, err)
    
  • server/public/model/remote_cluster.go+6 4 modified
    @@ -363,10 +363,12 @@ type RemoteClusterPing struct {
     
     // RemoteClusterInvite represents an invitation to establish a simple trust with a remote cluster.
     type RemoteClusterInvite struct {
    -	RemoteId     string `json:"remote_id"`
    -	RemoteTeamId string `json:"remote_team_id"` // Deprecated: this field is no longer used. It's only kept for backwards compatibility.
    -	SiteURL      string `json:"site_url"`
    -	Token        string `json:"token"`
    +	RemoteId       string `json:"remote_id"`
    +	RemoteTeamId   string `json:"remote_team_id"` // Deprecated: this field is no longer used. It's only kept for backwards compatibility.
    +	SiteURL        string `json:"site_url"`
    +	Token          string `json:"token"`
    +	RefreshedToken string `json:"refreshed_token,omitempty"` // New token generated by the remote cluster when accepting an invitation
    +	Version        int    `json:"version,omitempty"`
     }
     
     func (rci *RemoteClusterInvite) IsValid() *AppError {
    
  • server/public/model/remote_cluster_test.go+5 3 modified
    @@ -160,9 +160,11 @@ func TestRemoteClusterInviteEncryption(t *testing.T) {
     
     func makeInvite(url string) RemoteClusterInvite {
     	return RemoteClusterInvite{
    -		RemoteId: NewId(),
    -		SiteURL:  url,
    -		Token:    NewId(),
    +		RemoteId:       NewId(),
    +		SiteURL:        url,
    +		Token:          NewId(),
    +		RefreshedToken: NewId(),
    +		Version:        2,
     	}
     }
     
    

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

4

News mentions

0

No linked articles in our index yet.