VYPR
Low severityNVD Advisory· Published Jun 11, 2025· Updated Jun 11, 2025

Mattermost Guest User Information Disclosure Vulnerability

CVE-2025-4128

Description

Mattermost versions 10.5.x <= 10.5.4, 9.11.x <= 9.11.13 fail to properly restrict API access to team information, allowing guest users to bypass permissions and view information about public teams they are not members of via a direct API call to /api/v4/teams/{team_id}.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/mattermost/mattermost/server/v8Go
< 8.0.0-20250422131222-701ddc896a108.0.0-20250422131222-701ddc896a10
github.com/mattermost/mattermost-serverGo
>= 10.5.0, < 10.5.510.5.5
github.com/mattermost/mattermost-serverGo
>= 9.11.0, < 9.11.149.11.14

Affected products

1

Patches

2
2138a5f2ca6f

MM-63791: guest permissions to teams (#30789) (#30874)

https://github.com/mattermost/mattermostMattermost BuildApr 29, 2025via ghsa
5 files changed · +122 19
  • server/channels/api4/apitestlib.go+7 12 modified
    @@ -656,7 +656,8 @@ func (th *TestHelper) CreateUserWithAuth(authService string) *model.User {
     // CreateGuestAndClient creates a guest user, adds them to the basic
     // team, basic channel and basic private channel, and generates an API
     // client ready to use
    -func (th *TestHelper) CreateGuestAndClient() (*model.User, *model.Client4) {
    +func (th *TestHelper) CreateGuestAndClient(tb testing.TB) (*model.User, *model.Client4) {
    +	tb.Helper()
     	id := model.NewId()
     
     	// create a guest user and add it to the basic team and public/private channels
    @@ -667,23 +668,17 @@ func (th *TestHelper) CreateGuestAndClient() (*model.User, *model.Client4) {
     		Password:      "Password1",
     		EmailVerified: true,
     	})
    -	if cgErr != nil {
    -		panic(cgErr)
    -	}
    +	require.Nil(tb, cgErr)
     
    -	_, _, tErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guest.Id, th.SystemAdminUser.Id)
    -	if tErr != nil {
    -		panic(tErr)
    -	}
    +	_, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guest.Id, th.SystemAdminUser.Id)
    +	require.Nil(tb, appErr)
     	th.AddUserToChannel(guest, th.BasicChannel)
     	th.AddUserToChannel(guest, th.BasicPrivateChannel)
     
     	// create a client and login the guest
     	guestClient := th.CreateClient()
    -	_, _, lErr := guestClient.Login(context.Background(), guest.Username, "Password1")
    -	if lErr != nil {
    -		panic(lErr)
    -	}
    +	_, _, err := guestClient.Login(context.Background(), guest.Email, "Password1")
    +	require.NoError(tb, err)
     
     	return guest, guestClient
     }
    
  • server/channels/api4/channel_bookmark_test.go+5 5 modified
    @@ -41,7 +41,7 @@ func TestCreateChannelBookmark(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user should be able to create a channel bookmark in a public channel", func(t *testing.T) {
     		channelBookmark := &model.ChannelBookmark{
    @@ -290,7 +290,7 @@ func TestEditChannelBookmark(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user editing a channel bookmark in public and private channels", func(t *testing.T) {
     		testCases := []struct {
    @@ -720,7 +720,7 @@ func TestUpdateChannelBookmarkSortOrder(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user updating a bookmark's order in public and private channels", func(t *testing.T) {
     		testCases := []struct {
    @@ -1085,7 +1085,7 @@ func TestDeleteChannelBookmark(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user deleting bookmarks in public and private channels", func(t *testing.T) {
     		testCases := []struct {
    @@ -1452,7 +1452,7 @@ func TestListChannelBookmarksForChannel(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	publicBookmark1 := createBookmark("one", th.BasicChannel.Id)
     	publicBookmark2 := createBookmark("two", th.BasicChannel.Id)
    
  • server/channels/api4/channel_test.go+1 1 modified
    @@ -3607,7 +3607,7 @@ func TestAddChannelMemberGuestAccessControl(t *testing.T) {
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
     	// Create a guest user
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	// Create a public channel to which the guest doesn't belong
     	publicChannel := th.CreatePublicChannel()
    
  • server/channels/api4/team.go+10 1 modified
    @@ -151,7 +151,16 @@ func getTeam(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    -	if (!team.AllowOpenInvite || team.Type != model.TeamOpen) && !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), team.Id, model.PermissionViewTeam) {
    +	isPublicTeam := team.AllowOpenInvite && team.Type == model.TeamOpen
    +	hasPermissionViewTeam := c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), team.Id, model.PermissionViewTeam)
    +
    +	if !isPublicTeam && !hasPermissionViewTeam {
    +		c.SetPermissionError(model.PermissionViewTeam)
    +		return
    +	}
    +
    +	if isPublicTeam && !hasPermissionViewTeam && !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionListPublicTeams) {
    +		// Fail with PermissionViewTeam, not PermissionListPublicTeams.
     		c.SetPermissionError(model.PermissionViewTeam)
     		return
     	}
    
  • server/channels/api4/team_guest_test.go+99 0 added
    @@ -0,0 +1,99 @@
    +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
    +// See LICENSE.txt for license information.
    +
    +package api4
    +
    +import (
    +	"context"
    +	"net/http"
    +	"testing"
    +
    +	"github.com/stretchr/testify/assert"
    +	"github.com/stretchr/testify/require"
    +
    +	"github.com/mattermost/mattermost/server/public/model"
    +)
    +
    +func TestGetTeamAsGuest(t *testing.T) {
    +	th := Setup(t).InitBasic()
    +	defer th.TearDown()
    +
    +	th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
    +	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
    +
    +	guest, guestClient := th.CreateGuestAndClient(t)
    +
    +	publicTeamNotAMember := &model.Team{
    +		DisplayName:     "Public Team (guest is not a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamOpen,
    +		AllowOpenInvite: true,
    +	}
    +	publicTeamNotAMember, _, err := th.SystemAdminClient.CreateTeam(context.Background(), publicTeamNotAMember)
    +	require.NoError(t, err)
    +
    +	publicTeamIsAMember := &model.Team{
    +		DisplayName:     "Public Team (guest is a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamOpen,
    +		AllowOpenInvite: true,
    +	}
    +	publicTeamIsAMember, _, err = th.SystemAdminClient.CreateTeam(context.Background(), publicTeamIsAMember)
    +	require.NoError(t, err)
    +
    +	_, _, err = th.SystemAdminClient.AddTeamMember(context.Background(), publicTeamIsAMember.Id, guest.Id)
    +	require.NoError(t, err)
    +
    +	privateTeamNotAMember := &model.Team{
    +		DisplayName:     "Private Team (guest is not a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamInvite,
    +		AllowOpenInvite: false,
    +	}
    +	privateTeamNotAMember, _, err = th.SystemAdminClient.CreateTeam(context.Background(), privateTeamNotAMember)
    +	require.NoError(t, err)
    +
    +	privateTeamIsAMember := &model.Team{
    +		DisplayName:     "Private Team (guest is not a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamInvite,
    +		AllowOpenInvite: false,
    +	}
    +	privateTeamIsAMember, _, err = th.SystemAdminClient.CreateTeam(context.Background(), privateTeamIsAMember)
    +	require.NoError(t, err)
    +
    +	_, _, err = th.SystemAdminClient.AddTeamMember(context.Background(), privateTeamIsAMember.Id, guest.Id)
    +	require.NoError(t, err)
    +
    +	t.Run("guest cannot view public team they are not a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), publicTeamNotAMember.Id, "")
    +		require.Error(t, err)
    +		require.Equal(t, http.StatusForbidden, resp.StatusCode)
    +		assert.Nil(t, team)
    +	})
    +
    +	t.Run("guest can view public team they are a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), publicTeamIsAMember.Id, "")
    +		require.NoError(t, err)
    +		require.Equal(t, http.StatusOK, resp.StatusCode)
    +		assert.Equal(t, publicTeamIsAMember.Id, team.Id)
    +	})
    +
    +	t.Run("guest can not view private team they are not a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), privateTeamNotAMember.Id, "")
    +		require.Error(t, err)
    +		require.Equal(t, http.StatusForbidden, resp.StatusCode)
    +		assert.Nil(t, team)
    +	})
    +
    +	t.Run("guest can view private team they are a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), privateTeamIsAMember.Id, "")
    +		require.NoError(t, err)
    +		require.Equal(t, http.StatusOK, resp.StatusCode)
    +		assert.Equal(t, privateTeamIsAMember.Id, team.Id)
    +	})
    +}
    
701ddc896a10

MM-63791: guest permissions to teams (#30789)

https://github.com/mattermost/mattermostJesse HallamApr 22, 2025via ghsa
5 files changed · +122 19
  • server/channels/api4/apitestlib.go+7 12 modified
    @@ -695,7 +695,8 @@ func (th *TestHelper) CreateUserWithAuth(authService string) *model.User {
     // CreateGuestAndClient creates a guest user, adds them to the basic
     // team, basic channel and basic private channel, and generates an API
     // client ready to use
    -func (th *TestHelper) CreateGuestAndClient() (*model.User, *model.Client4) {
    +func (th *TestHelper) CreateGuestAndClient(tb testing.TB) (*model.User, *model.Client4) {
    +	tb.Helper()
     	id := model.NewId()
     
     	// create a guest user and add it to the basic team and public/private channels
    @@ -706,23 +707,17 @@ func (th *TestHelper) CreateGuestAndClient() (*model.User, *model.Client4) {
     		Password:      "Password1",
     		EmailVerified: true,
     	})
    -	if cgErr != nil {
    -		panic(cgErr)
    -	}
    +	require.Nil(tb, cgErr)
     
    -	_, _, tErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guest.Id, th.SystemAdminUser.Id)
    -	if tErr != nil {
    -		panic(tErr)
    -	}
    +	_, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guest.Id, th.SystemAdminUser.Id)
    +	require.Nil(tb, appErr)
     	th.AddUserToChannel(guest, th.BasicChannel)
     	th.AddUserToChannel(guest, th.BasicPrivateChannel)
     
     	// create a client and login the guest
     	guestClient := th.CreateClient()
    -	_, _, lErr := guestClient.Login(context.Background(), guest.Username, "Password1")
    -	if lErr != nil {
    -		panic(lErr)
    -	}
    +	_, _, err := guestClient.Login(context.Background(), guest.Email, "Password1")
    +	require.NoError(tb, err)
     
     	return guest, guestClient
     }
    
  • server/channels/api4/channel_bookmark_test.go+5 5 modified
    @@ -41,7 +41,7 @@ func TestCreateChannelBookmark(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user should be able to create a channel bookmark in a public channel", func(t *testing.T) {
     		channelBookmark := &model.ChannelBookmark{
    @@ -297,7 +297,7 @@ func TestEditChannelBookmark(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user editing a channel bookmark in public and private channels", func(t *testing.T) {
     		testCases := []struct {
    @@ -732,7 +732,7 @@ func TestUpdateChannelBookmarkSortOrder(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user updating a bookmark's order in public and private channels", func(t *testing.T) {
     		testCases := []struct {
    @@ -1121,7 +1121,7 @@ func TestDeleteChannelBookmark(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	t.Run("a user deleting bookmarks in public and private channels", func(t *testing.T) {
     		testCases := []struct {
    @@ -1494,7 +1494,7 @@ func TestListChannelBookmarksForChannel(t *testing.T) {
     	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	publicBookmark1 := createBookmark("one", th.BasicChannel.Id)
     	publicBookmark2 := createBookmark("two", th.BasicChannel.Id)
    
  • server/channels/api4/channel_test.go+1 1 modified
    @@ -4102,7 +4102,7 @@ func TestAddChannelMemberGuestAccessControl(t *testing.T) {
     	th.App.Srv().SetLicense(model.NewTestLicense())
     
     	// Create a guest user
    -	guest, guestClient := th.CreateGuestAndClient()
    +	guest, guestClient := th.CreateGuestAndClient(t)
     
     	// Create a public channel to which the guest doesn't belong
     	publicChannel := th.CreatePublicChannel()
    
  • server/channels/api4/team.go+10 1 modified
    @@ -151,7 +151,16 @@ func getTeam(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    -	if (!team.AllowOpenInvite || team.Type != model.TeamOpen) && !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), team.Id, model.PermissionViewTeam) {
    +	isPublicTeam := team.AllowOpenInvite && team.Type == model.TeamOpen
    +	hasPermissionViewTeam := c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), team.Id, model.PermissionViewTeam)
    +
    +	if !isPublicTeam && !hasPermissionViewTeam {
    +		c.SetPermissionError(model.PermissionViewTeam)
    +		return
    +	}
    +
    +	if isPublicTeam && !hasPermissionViewTeam && !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionListPublicTeams) {
    +		// Fail with PermissionViewTeam, not PermissionListPublicTeams.
     		c.SetPermissionError(model.PermissionViewTeam)
     		return
     	}
    
  • server/channels/api4/team_guest_test.go+99 0 added
    @@ -0,0 +1,99 @@
    +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
    +// See LICENSE.txt for license information.
    +
    +package api4
    +
    +import (
    +	"context"
    +	"net/http"
    +	"testing"
    +
    +	"github.com/stretchr/testify/assert"
    +	"github.com/stretchr/testify/require"
    +
    +	"github.com/mattermost/mattermost/server/public/model"
    +)
    +
    +func TestGetTeamAsGuest(t *testing.T) {
    +	th := Setup(t).InitBasic()
    +	defer th.TearDown()
    +
    +	th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
    +	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
    +
    +	guest, guestClient := th.CreateGuestAndClient(t)
    +
    +	publicTeamNotAMember := &model.Team{
    +		DisplayName:     "Public Team (guest is not a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamOpen,
    +		AllowOpenInvite: true,
    +	}
    +	publicTeamNotAMember, _, err := th.SystemAdminClient.CreateTeam(context.Background(), publicTeamNotAMember)
    +	require.NoError(t, err)
    +
    +	publicTeamIsAMember := &model.Team{
    +		DisplayName:     "Public Team (guest is a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamOpen,
    +		AllowOpenInvite: true,
    +	}
    +	publicTeamIsAMember, _, err = th.SystemAdminClient.CreateTeam(context.Background(), publicTeamIsAMember)
    +	require.NoError(t, err)
    +
    +	_, _, err = th.SystemAdminClient.AddTeamMember(context.Background(), publicTeamIsAMember.Id, guest.Id)
    +	require.NoError(t, err)
    +
    +	privateTeamNotAMember := &model.Team{
    +		DisplayName:     "Private Team (guest is not a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamInvite,
    +		AllowOpenInvite: false,
    +	}
    +	privateTeamNotAMember, _, err = th.SystemAdminClient.CreateTeam(context.Background(), privateTeamNotAMember)
    +	require.NoError(t, err)
    +
    +	privateTeamIsAMember := &model.Team{
    +		DisplayName:     "Private Team (guest is not a member)",
    +		Name:            GenerateTestTeamName(),
    +		Email:           th.GenerateTestEmail(),
    +		Type:            model.TeamInvite,
    +		AllowOpenInvite: false,
    +	}
    +	privateTeamIsAMember, _, err = th.SystemAdminClient.CreateTeam(context.Background(), privateTeamIsAMember)
    +	require.NoError(t, err)
    +
    +	_, _, err = th.SystemAdminClient.AddTeamMember(context.Background(), privateTeamIsAMember.Id, guest.Id)
    +	require.NoError(t, err)
    +
    +	t.Run("guest cannot view public team they are not a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), publicTeamNotAMember.Id, "")
    +		require.Error(t, err)
    +		require.Equal(t, http.StatusForbidden, resp.StatusCode)
    +		assert.Nil(t, team)
    +	})
    +
    +	t.Run("guest can view public team they are a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), publicTeamIsAMember.Id, "")
    +		require.NoError(t, err)
    +		require.Equal(t, http.StatusOK, resp.StatusCode)
    +		assert.Equal(t, publicTeamIsAMember.Id, team.Id)
    +	})
    +
    +	t.Run("guest can not view private team they are not a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), privateTeamNotAMember.Id, "")
    +		require.Error(t, err)
    +		require.Equal(t, http.StatusForbidden, resp.StatusCode)
    +		assert.Nil(t, team)
    +	})
    +
    +	t.Run("guest can view private team they are a member of", func(t *testing.T) {
    +		team, resp, err := guestClient.GetTeam(context.Background(), privateTeamIsAMember.Id, "")
    +		require.NoError(t, err)
    +		require.Equal(t, http.StatusOK, resp.StatusCode)
    +		assert.Equal(t, privateTeamIsAMember.Id, team.Id)
    +	})
    +}
    

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.