VYPR
Low severityNVD Advisory· Published Oct 16, 2025· Updated Oct 16, 2025

Guest user can add unauthorized team users to private channels

CVE-2025-10545

Description

Mattermost versions 10.5.x <= 10.5.10, 10.11.x <= 10.11.2 fail to properly validate guest user permissions when adding channel members which allows guest users to add any team members to their private channels via the /api/v4/channels/{channel_id}/members endpoint

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/mattermost/mattermost/server/v8Go
< 8.0.0-20250820115038-ff30b84049f08.0.0-20250820115038-ff30b84049f0
github.com/mattermost/mattermost-serverGo
>= 10.5.0, < 10.5.1110.5.11
github.com/mattermost/mattermost-serverGo
>= 10.11.0, < 10.11.310.11.3

Affected products

1

Patches

2
fb9c583f5e46

[MM-64445] api4/channels_test: Add tests cases for guest user private channels (#31319) (#33827)

https://github.com/mattermost/mattermostIbrahim Serdar AcikgozSep 2, 2025via ghsa
2 files changed · +106 5
  • server/channels/api4/channel.go+16 3 modified
    @@ -1831,9 +1831,22 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
     
     	// Security check: if the user is a guest, they must have access to the channel
     	// to view its members
    -	if c.AppContext.Session().IsGuest() && !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionReadChannel) {
    -		c.SetPermissionError(model.PermissionReadChannel)
    -		return
    +	if c.AppContext.Session().IsGuest() {
    +		if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionReadChannel) {
    +			c.SetPermissionError(model.PermissionReadChannel)
    +			return
    +		}
    +		for _, userId := range userIds {
    +			allowed, appErr := c.App.UserCanSeeOtherUser(c.AppContext, c.AppContext.Session().UserId, userId)
    +			if appErr != nil {
    +				c.Err = appErr
    +				return
    +			}
    +			if !allowed {
    +				c.SetPermissionError(model.PermissionInviteUser)
    +				return
    +			}
    +		}
     	}
     
     	if channel.Type == model.ChannelTypeDirect || channel.Type == model.ChannelTypeGroup {
    
  • server/channels/api4/channel_test.go+90 2 modified
    @@ -149,18 +149,106 @@ func TestCreateChannel(t *testing.T) {
     	t.Run("Test create channel with missing team id", func(t *testing.T) {
     		channel := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: ""}
     
    -		_, resp, err := client.CreateChannel(context.Background(), channel)
    +		_, resp, err = client.CreateChannel(context.Background(), channel)
     		CheckErrorID(t, err, "api.context.invalid_body_param.app_error")
     		CheckBadRequestStatus(t, resp)
     	})
     
     	t.Run("Test create channel with missing display name", func(t *testing.T) {
     		channel := &model.Channel{DisplayName: "", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: team.Id}
     
    -		_, resp, err := client.CreateChannel(context.Background(), channel)
    +		_, resp, err = client.CreateChannel(context.Background(), channel)
     		CheckErrorID(t, err, "api.context.invalid_body_param.app_error")
     		CheckBadRequestStatus(t, resp)
     	})
    +
    +	t.Run("Guest users", func(t *testing.T) {
    +		th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
    +		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
    +		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.AllowEmailAccounts = true })
    +
    +		guestUser := th.CreateUser()
    +		appErr := th.App.VerifyUserEmail(guestUser.Id, guestUser.Email)
    +		require.Nil(t, appErr)
    +
    +		appErr = th.App.DemoteUserToGuest(th.Context, guestUser)
    +		require.Nil(t, appErr)
    +
    +		_, _, appErr = th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guestUser.Id, "")
    +		require.Nil(t, appErr)
    +
    +		guestClient := th.CreateClient()
    +		_, _, err := guestClient.Login(context.Background(), guestUser.Username, guestUser.Password)
    +		require.NoError(t, err)
    +		t.Cleanup(func() {
    +			_, lErr := guestClient.Logout(context.Background())
    +			require.NoError(t, lErr)
    +		})
    +
    +		userOutsideOfChannels := th.CreateUser()
    +		_, _, err = th.Client.AddTeamMember(context.Background(), team.Id, userOutsideOfChannels.Id)
    +		require.NoError(t, err)
    +
    +		public := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: team.Id}
    +		private := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypePrivate, TeamId: team.Id}
    +
    +		t.Run("Guest user should not be able to create channels", func(t *testing.T) {
    +			_, resp, err = guestClient.CreateChannel(context.Background(), public)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +
    +			private.Name = GenerateTestChannelName()
    +			_, resp, err = guestClient.CreateChannel(context.Background(), private)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +		})
    +
    +		t.Run("Guest user should not be able to add channel members if they have no common channels", func(t *testing.T) {
    +			// Now actually create the channels with the main client
    +			public, _, err = th.Client.CreateChannel(context.Background(), public)
    +			require.NoError(t, err)
    +			private, _, err = th.Client.CreateChannel(context.Background(), private)
    +			require.NoError(t, err)
    +
    +			// Add the guest user to the private channel
    +			_, _, err = th.Client.AddChannelMember(context.Background(), private.Id, guestUser.Id)
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user can access the private channel they were added to
    +			_, _, err = guestClient.GetChannel(context.Background(), private.Id, "")
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user cannot add members to the private channel
    +			_, resp, err = guestClient.AddChannelMember(context.Background(), private.Id, userOutsideOfChannels.Id)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +
    +			// Add the guest user to the public channel
    +			_, _, err = th.Client.AddChannelMember(context.Background(), public.Id, guestUser.Id)
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user can access the public channel they were added to
    +			_, _, err = guestClient.GetChannel(context.Background(), public.Id, "")
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user cannot add members to the public channel
    +			_, resp, err = guestClient.AddChannelMember(context.Background(), public.Id, userOutsideOfChannels.Id)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +
    +			// Update team guest permissions to allow creating private channels
    +			th.AddPermissionToRole(model.PermissionCreatePrivateChannel.Id, model.TeamGuestRoleId)
    +			privateGuest := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypePrivate, TeamId: team.Id}
    +			privateGuest, resp, err = guestClient.CreateChannel(context.Background(), privateGuest)
    +			require.NoError(t, err)
    +			CheckCreatedStatus(t, resp)
    +
    +			// Verify that the guest user can't add users they have no visibility to
    +			_, resp, err = guestClient.AddChannelMember(context.Background(), privateGuest.Id, userOutsideOfChannels.Id)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +		})
    +	})
     }
     
     func TestUpdateChannel(t *testing.T) {
    
ff30b84049f0

[MM-64445] api4/channels_test: Add tests cases for guest user private channels (#31319)

https://github.com/mattermost/mattermostIbrahim Serdar AcikgozAug 20, 2025via ghsa
2 files changed · +109 7
  • server/channels/api4/channel.go+16 3 modified
    @@ -1857,9 +1857,22 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
     
     	// Security check: if the user is a guest, they must have access to the channel
     	// to view its members
    -	if c.AppContext.Session().IsGuest() && !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionReadChannel) {
    -		c.SetPermissionError(model.PermissionReadChannel)
    -		return
    +	if c.AppContext.Session().IsGuest() {
    +		if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionReadChannel) {
    +			c.SetPermissionError(model.PermissionReadChannel)
    +			return
    +		}
    +		for _, userId := range userIds {
    +			allowed, appErr := c.App.UserCanSeeOtherUser(c.AppContext, c.AppContext.Session().UserId, userId)
    +			if appErr != nil {
    +				c.Err = appErr
    +				return
    +			}
    +			if !allowed {
    +				c.SetPermissionError(model.PermissionInviteUser)
    +				return
    +			}
    +		}
     	}
     
     	if channel.Type == model.ChannelTypeDirect || channel.Type == model.ChannelTypeGroup {
    
  • server/channels/api4/channel_test.go+93 4 modified
    @@ -152,15 +152,15 @@ func TestCreateChannel(t *testing.T) {
     	t.Run("Test create channel with missing team id", func(t *testing.T) {
     		channel := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: ""}
     
    -		_, resp, err := client.CreateChannel(context.Background(), channel)
    +		_, resp, err = client.CreateChannel(context.Background(), channel)
     		CheckErrorID(t, err, "api.context.invalid_body_param.app_error")
     		CheckBadRequestStatus(t, resp)
     	})
     
     	t.Run("Test create channel with missing display name", func(t *testing.T) {
     		channel := &model.Channel{DisplayName: "", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: team.Id}
     
    -		_, resp, err := client.CreateChannel(context.Background(), channel)
    +		_, resp, err = client.CreateChannel(context.Background(), channel)
     		CheckErrorID(t, err, "api.context.invalid_body_param.app_error")
     		CheckBadRequestStatus(t, resp)
     	})
    @@ -178,7 +178,8 @@ func TestCreateChannel(t *testing.T) {
     			},
     		}
     
    -		createdChannel, resp, err := client.CreateChannel(context.Background(), channel)
    +		var createdChannel *model.Channel
    +		createdChannel, resp, err = client.CreateChannel(context.Background(), channel)
     		require.NoError(t, err)
     		CheckCreatedStatus(t, resp)
     
    @@ -198,10 +199,98 @@ func TestCreateChannel(t *testing.T) {
     			},
     		}
     
    -		_, resp, err := client.CreateChannel(context.Background(), channel)
    +		_, resp, err = client.CreateChannel(context.Background(), channel)
     		CheckErrorID(t, err, "api.context.invalid_body_param.app_error")
     		CheckBadRequestStatus(t, resp)
     	})
    +
    +	t.Run("Guest users", func(t *testing.T) {
    +		th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
    +		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
    +		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.AllowEmailAccounts = true })
    +
    +		guestUser := th.CreateUser()
    +		appErr := th.App.VerifyUserEmail(guestUser.Id, guestUser.Email)
    +		require.Nil(t, appErr)
    +
    +		appErr = th.App.DemoteUserToGuest(th.Context, guestUser)
    +		require.Nil(t, appErr)
    +
    +		_, _, appErr = th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, guestUser.Id, "")
    +		require.Nil(t, appErr)
    +
    +		guestClient := th.CreateClient()
    +		_, _, err := guestClient.Login(context.Background(), guestUser.Username, guestUser.Password)
    +		require.NoError(t, err)
    +		t.Cleanup(func() {
    +			_, lErr := guestClient.Logout(context.Background())
    +			require.NoError(t, lErr)
    +		})
    +
    +		userOutsideOfChannels := th.CreateUser()
    +		_, _, err = th.Client.AddTeamMember(context.Background(), team.Id, userOutsideOfChannels.Id)
    +		require.NoError(t, err)
    +
    +		public := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: team.Id}
    +		private := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypePrivate, TeamId: team.Id}
    +
    +		t.Run("Guest user should not be able to create channels", func(t *testing.T) {
    +			_, resp, err = guestClient.CreateChannel(context.Background(), public)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +
    +			private.Name = GenerateTestChannelName()
    +			_, resp, err = guestClient.CreateChannel(context.Background(), private)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +		})
    +
    +		t.Run("Guest user should not be able to add channel members if they have no common channels", func(t *testing.T) {
    +			// Now actually create the channels with the main client
    +			public, _, err = th.Client.CreateChannel(context.Background(), public)
    +			require.NoError(t, err)
    +			private, _, err = th.Client.CreateChannel(context.Background(), private)
    +			require.NoError(t, err)
    +
    +			// Add the guest user to the private channel
    +			_, _, err = th.Client.AddChannelMember(context.Background(), private.Id, guestUser.Id)
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user can access the private channel they were added to
    +			_, _, err = guestClient.GetChannel(context.Background(), private.Id, "")
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user cannot add members to the private channel
    +			_, resp, err = guestClient.AddChannelMember(context.Background(), private.Id, userOutsideOfChannels.Id)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +
    +			// Add the guest user to the public channel
    +			_, _, err = th.Client.AddChannelMember(context.Background(), public.Id, guestUser.Id)
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user can access the public channel they were added to
    +			_, _, err = guestClient.GetChannel(context.Background(), public.Id, "")
    +			require.NoError(t, err)
    +
    +			// Verify that the guest user cannot add members to the public channel
    +			_, resp, err = guestClient.AddChannelMember(context.Background(), public.Id, userOutsideOfChannels.Id)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +
    +			// Update team guest permissions to allow creating private channels
    +			th.AddPermissionToRole(model.PermissionCreatePrivateChannel.Id, model.TeamGuestRoleId)
    +			privateGuest := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.ChannelTypePrivate, TeamId: team.Id}
    +			privateGuest, resp, err = guestClient.CreateChannel(context.Background(), privateGuest)
    +			require.NoError(t, err)
    +			CheckCreatedStatus(t, resp)
    +
    +			// Verify that the guest user can't add users they have no visibility to
    +			_, resp, err = guestClient.AddChannelMember(context.Background(), privateGuest.Id, userOutsideOfChannels.Id)
    +			require.Error(t, err)
    +			CheckForbiddenStatus(t, resp)
    +		})
    +	})
     }
     
     func TestUpdateChannel(t *testing.T) {
    

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

7

News mentions

0

No linked articles in our index yet.