Moderate severityNVD Advisory· Published May 29, 2025· Updated May 29, 2025
Team Privacy Settings Authorization Bypass in Mattermost Server
CVE-2025-3913
Description
Mattermost versions 10.7.x <= 10.7.0, 10.6.x <= 10.6.2, 10.5.x <= 10.5.3, 9.11.x <= 9.11.12 fail to properly validate permissions when changing team privacy settings, allowing team administrators without the 'invite user' permission to access and modify team invite IDs via the /api/v4/teams/:teamId/privacy endpoint.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/mattermost/mattermost/server/v8Go | >= 10.7.0-rc1, < 10.7.1 | 10.7.1 |
github.com/mattermost/mattermost/server/v8Go | >= 10.6.0-rc1, < 10.6.3 | 10.6.3 |
github.com/mattermost/mattermost/server/v8Go | >= 10.5.0-rc1, < 10.5.4 | 10.5.4 |
github.com/mattermost/mattermost/server/v8Go | >= 9.0.0-rc1, < 9.11.13 | 9.11.13 |
github.com/mattermost/mattermost/server/v8Go | < 8.0.0-20250412152950-02c76784380a | 8.0.0-20250412152950-02c76784380a |
Affected products
1- Range: 10.7.0
Patches
102c76784380aMM-63590 - validate user has proper permission when updating team privacy (#30650)
2 files changed · +87 −0
server/channels/api4/team.go+5 −0 modified@@ -382,6 +382,11 @@ func updateTeamPrivacy(c *Context, w http.ResponseWriter, r *http.Request) { return } + if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), c.Params.TeamId, model.PermissionInviteUser) { + c.SetPermissionError(model.PermissionInviteUser) + return + } + if err := c.App.UpdateTeamPrivacy(c.Params.TeamId, privacy, openInvite); err != nil { c.Err = err return
server/channels/api4/team_test.go+82 −0 modified@@ -497,6 +497,88 @@ func TestUpdateTeam(t *testing.T) { }) } +func TestUpdateTeamPrivacyInvitePermissions(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + client := th.Client + + // Create a team with AllowOpenInvite=true and Type=TeamOpen + team := &model.Team{ + DisplayName: "Test Team", + Name: GenerateTestTeamName(), + Email: th.GenerateTestEmail(), + Type: model.TeamOpen, + AllowOpenInvite: true, + } + team, _, err := client.CreateTeam(context.Background(), team) + require.NoError(t, err) + + // Save the original invite ID + originalInviteId := team.InviteId + + // Test case: User with InviteUser permission can change privacy settings that regenerate invite ID + t.Run("user with invite permission can change privacy", func(t *testing.T) { + // Ensure the user has the InviteUser permission + th.AddPermissionToRole(model.PermissionInviteUser.Id, model.TeamUserRoleId) + + // Change from Open to Invite (should regenerate invite ID) + _, resp, err := client.UpdateTeamPrivacy(context.Background(), team.Id, model.TeamInvite) + require.NoError(t, err) + CheckOKStatus(t, resp) + + // Verify the team's invite ID was regenerated + updatedTeam, _, err := client.GetTeam(context.Background(), team.Id, "") + require.NoError(t, err) + require.NotEqual(t, originalInviteId, updatedTeam.InviteId, "InviteId should have been regenerated") + require.Equal(t, model.TeamInvite, updatedTeam.Type, "Team type should be Invite") + require.False(t, updatedTeam.AllowOpenInvite, "AllowOpenInvite should be false") + }) + + // Test case: User without InviteUser permission cannot change privacy settings that regenerate invite ID + t.Run("user without invite permission cannot change privacy", func(t *testing.T) { + // First, make sure the team is in a state where changing privacy will regenerate invite ID + // Change to Open type first + _, resp, err := client.UpdateTeamPrivacy(context.Background(), team.Id, model.TeamOpen) + require.NoError(t, err) + CheckOKStatus(t, resp) + + // Verify the team's privacy settings changed + updatedTeam, _, err := client.GetTeam(context.Background(), team.Id, "") + require.NoError(t, err) + require.Equal(t, model.TeamOpen, updatedTeam.Type, "Team type should be Open") + require.True(t, updatedTeam.AllowOpenInvite, "AllowOpenInvite should be true") + + // Now remove the InviteUser permission from both team user and team admin roles + th.RemovePermissionFromRole(model.PermissionInviteUser.Id, model.TeamUserRoleId) + th.RemovePermissionFromRole(model.PermissionInviteUser.Id, model.TeamAdminRoleId) + + // Try to change from Open to Invite (should fail because this would regenerate invite ID) + _, resp, err = client.UpdateTeamPrivacy(context.Background(), team.Id, model.TeamInvite) + require.Error(t, err) + CheckForbiddenStatus(t, resp) + + // Verify the team's privacy settings didn't change + updatedTeam, _, err = th.SystemAdminClient.GetTeam(context.Background(), team.Id, "") + require.NoError(t, err) + require.Equal(t, model.TeamOpen, updatedTeam.Type, "Team type should still be Open") + require.True(t, updatedTeam.AllowOpenInvite, "AllowOpenInvite should still be true") + }) + + // Test case: System admin can change privacy settings regardless of permissions + t.Run("system admin can change privacy", func(t *testing.T) { + // Change from Invite to Open using system admin + _, resp, err := th.SystemAdminClient.UpdateTeamPrivacy(context.Background(), team.Id, model.TeamOpen) + require.NoError(t, err) + CheckOKStatus(t, resp) + + // Verify the team's privacy settings changed + updatedTeam, _, err := th.SystemAdminClient.GetTeam(context.Background(), team.Id, "") + require.NoError(t, err) + require.Equal(t, model.TeamOpen, updatedTeam.Type, "Team type should be Open") + require.True(t, updatedTeam.AllowOpenInvite, "AllowOpenInvite should be true") + }) +} + func TestUpdateTeamSanitization(t *testing.T) { th := Setup(t) defer th.TearDown()
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
4News mentions
0No linked articles in our index yet.