Moderate severityNVD Advisory· Published Oct 16, 2025· Updated Oct 29, 2025
Guest user can discover active public channels
CVE-2025-41443
Description
Mattermost versions 10.5.x <= 10.5.12, 10.11.x <= 10.11.2 fail to properly validate guest user permissions when accessing channel information which allows guest users to discover active public channels and their metadata via the /api/v4/teams/{team_id}/channels/ids endpoint
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/mattermost/mattermost/server/v8Go | < 8.0.0-20250822090405-e8c7e7d0252b | 8.0.0-20250822090405-e8c7e7d0252b |
github.com/mattermost/mattermost-serverGo | >= 10.5.0, < 10.5.11 | 10.5.11 |
github.com/mattermost/mattermost-serverGo | >= 10.11.0, < 10.11.3 | 10.11.3 |
Affected products
1- Range: 10.5.0
Patches
1e8c7e7d0252b[MM-64453] Guest shouldn't discover public channels that they are not member of (#31327) (#33778)
2 files changed · +103 −39
server/channels/api4/channel.go+9 −0 modified@@ -999,6 +999,15 @@ func getPublicChannelsByIdsForTeam(c *Context, w http.ResponseWriter, r *http.Re return } + if session := c.AppContext.Session(); session.IsGuest() { + for _, channel := range channels { + if !c.App.SessionHasPermissionToChannel(c.AppContext, *session, channel.Id, model.PermissionReadChannel) { + c.SetPermissionError(model.PermissionReadChannel) + return + } + } + } + appErr = c.App.FillInChannelsProps(c.AppContext, channels) if appErr != nil { c.Err = appErr
server/channels/api4/channel_test.go+94 −39 modified@@ -1906,57 +1906,112 @@ func TestGetPublicChannelsByIdsForTeam(t *testing.T) { defer th.TearDown() client := th.Client teamId := th.BasicTeam.Id - input := []string{th.BasicChannel.Id} - output := []string{th.BasicChannel.DisplayName} - channels, _, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) - require.NoError(t, err) - require.Len(t, channels, 1, "should return 1 channel") - require.Equal(t, output[0], channels[0].DisplayName, "missing channel") + t.Run("should return 1 channel", func(t *testing.T) { + input := []string{th.BasicChannel.Id} + output := []string{th.BasicChannel.DisplayName} - input = append(input, GenerateTestID()) - input = append(input, th.BasicChannel2.Id) - input = append(input, th.BasicPrivateChannel.Id) - output = append(output, th.BasicChannel2.DisplayName) - sort.Strings(output) + channels, _, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) + require.NoError(t, err) + require.Len(t, channels, 1, "should return 1 channel") + require.Equal(t, output[0], channels[0].DisplayName, "missing channel") + }) - channels, _, err = client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) - require.NoError(t, err) - require.Len(t, channels, 2, "should return 2 channels") + t.Run("should return 2 channels", func(t *testing.T) { + input := []string{th.BasicChannel.Id} + output := []string{th.BasicChannel.DisplayName} - for i, c := range channels { - require.Equal(t, output[i], c.DisplayName, "missing channel") - } + input = append(input, GenerateTestID()) + input = append(input, th.BasicChannel2.Id) + input = append(input, th.BasicPrivateChannel.Id) + output = append(output, th.BasicChannel2.DisplayName) + sort.Strings(output) - _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), GenerateTestID(), input) - require.Error(t, err) - CheckForbiddenStatus(t, resp) + channels, _, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) + require.NoError(t, err) + require.Len(t, channels, 2, "should return 2 channels") - _, resp, err = client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{}) - require.Error(t, err) - CheckBadRequestStatus(t, resp) + for i, c := range channels { + require.Equal(t, output[i], c.DisplayName, "missing channel") + } + }) - _, resp, err = client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{"junk"}) - require.Error(t, err) - CheckBadRequestStatus(t, resp) + t.Run("forbidden for invalid team", func(t *testing.T) { + input := []string{th.BasicChannel.Id, th.BasicChannel2.Id} + _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), GenerateTestID(), input) + require.Error(t, err) + CheckForbiddenStatus(t, resp) + }) - _, resp, err = client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{GenerateTestID()}) - require.Error(t, err) - CheckNotFoundStatus(t, resp) + t.Run("bad request for empty input", func(t *testing.T) { + _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{}) + require.Error(t, err) + CheckBadRequestStatus(t, resp) + }) - _, resp, err = client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{th.BasicPrivateChannel.Id}) - require.Error(t, err) - CheckNotFoundStatus(t, resp) + t.Run("bad request for junk id", func(t *testing.T) { + _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{"junk"}) + require.Error(t, err) + CheckBadRequestStatus(t, resp) + }) - _, err = client.Logout(context.Background()) - require.NoError(t, err) + t.Run("not found for non-existent id", func(t *testing.T) { + _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{GenerateTestID()}) + require.Error(t, err) + CheckNotFoundStatus(t, resp) + }) - _, resp, err = client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) - require.Error(t, err) - CheckUnauthorizedStatus(t, resp) + t.Run("not found for private channel id", func(t *testing.T) { + _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, []string{th.BasicPrivateChannel.Id}) + require.Error(t, err) + CheckNotFoundStatus(t, resp) + }) - _, _, err = th.SystemAdminClient.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) - require.NoError(t, err) + t.Run("unauthorized when logged out", func(t *testing.T) { + input := []string{th.BasicChannel.Id, th.BasicChannel2.Id} + _, lErr := client.Logout(context.Background()) + require.NoError(t, lErr) + + _, resp, err := client.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) + require.Error(t, err) + CheckUnauthorizedStatus(t, resp) + }) + + t.Run("system admin can get channels", func(t *testing.T) { + input := []string{th.BasicChannel.Id, th.BasicChannel2.Id} + _, _, err := th.SystemAdminClient.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) + require.NoError(t, err) + }) + + t.Run("guest users should not be able to get channels", 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 }) + + id := model.NewId() + guest := &model.User{ + Email: "success+" + id + "@simulator.amazonses.com", + Username: "un_" + id, + Nickname: "nn_" + id, + Password: "Password1", + EmailVerified: true, + } + guest, appErr := th.App.CreateGuest(th.Context, guest) + require.Nil(t, appErr) + + guestClient := th.CreateClient() + _, _, err := guestClient.Login(context.Background(), guest.Username, "Password1") + require.NoError(t, err) + t.Cleanup(func() { + _, lErr := guestClient.Logout(context.Background()) + require.NoError(t, lErr) + }) + + input := []string{th.BasicChannel.Id, th.BasicChannel2.Id} + _, resp, err := guestClient.GetPublicChannelsByIdsForTeam(context.Background(), teamId, input) + require.Error(t, err) + CheckForbiddenStatus(t, resp) + }) } func TestGetChannelsForTeamForUser(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
6- github.com/advisories/GHSA-7cr3-38jm-6p45ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-41443ghsaADVISORY
- github.com/mattermost/mattermost/commit/e8c7e7d0252bbf1e098aae4a5ea05d945afd7e70ghsaWEB
- github.com/mattermost/mattermost/pull/31327ghsaWEB
- github.com/mattermost/mattermost/pull/33778ghsaWEB
- mattermost.com/security-updatesghsaWEB
News mentions
0No linked articles in our index yet.