VYPR
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.

PackageAffected versionsPatched versions
github.com/mattermost/mattermost/server/v8Go
>= 10.7.0-rc1, < 10.7.110.7.1
github.com/mattermost/mattermost/server/v8Go
>= 10.6.0-rc1, < 10.6.310.6.3
github.com/mattermost/mattermost/server/v8Go
>= 10.5.0-rc1, < 10.5.410.5.4
github.com/mattermost/mattermost/server/v8Go
>= 9.0.0-rc1, < 9.11.139.11.13
github.com/mattermost/mattermost/server/v8Go
< 8.0.0-20250412152950-02c76784380a8.0.0-20250412152950-02c76784380a

Affected products

1

Patches

1
02c76784380a

MM-63590 - validate user has proper permission when updating team privacy (#30650)

https://github.com/mattermost/mattermostPablo VélezApr 12, 2025via ghsa
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

4

News mentions

0

No linked articles in our index yet.