How to stop players joining guard, staff or VIP teams

Team menus, auto-assigned teams and team spawns can put anyone on a team with extra powers. How to check who may join each team on the server.

criticalLuaudit check: client-chosen-teams

What it looks like

Some teams come with powers or perks: guards who can arrest, staff, a VIP team, a team with better weapons. The game means to limit who joins them, but a player can get onto the team anyway: a team-switch remote accepts any team the client names, the team is set to auto-assign, or its spawn changes the team of anyone who touches it.

Luau
remotes.JoinTeam.OnServerEvent:Connect(function(player, teamName)
	player.Team = Teams:FindFirstChild(teamName)
end)

How to detect it

  • List every team in Teams and work out which ones should be limited, by group rank, a pass, a level or a round role. Then search for code that gives those teams extra powers, such as player.Team == Teams.Guards checks in doors, tools and commands.
  • Find every place player.Team, player.TeamColor or player.Neutral is set from a remote, prompt or chat command. Check that the server applies the same rules for each team as the menu does. A menu that only shows open teams doesn't stop a client firing the remote with a limited one.
  • Check AutoAssignable on every limited team. Roblox's Team reference says joining players are put on the auto-assignable team with the fewest players, so a limited team left auto-assignable is handed to ordinary players as they join.
  • Check AllowTeamChangeOnTouch on every SpawnLocation of a limited team. Roblox's reference says it sets the team of any character that touches the spawn. Characters move under their player's control, so a wall or a locked door in front of the spawn doesn't stop them, as Restricted areas protected only by walls and doors explains.
  • Team changes in code that's run by a server-checked purchase, rank lookup or round system are fine. Follow the call back to its trigger.

What an exploiter could do

They join the guard, staff or VIP team without earning it and get everything that team allows: arresting or jailing other players, opening staff areas, using team-only weapons or claiming team perks. Other players see them as a real guard or staff member.

How to fix it

  • Decide on the server who may join each team, and check that rule wherever the team is set.
  • Turn off AutoAssignable on limited teams, and AllowTeamChangeOnTouch on their spawns.
  • Check the rule again when it can change, such as when a pass is refunded or a rank lookup fails.

Vulnerable example

Vulnerable
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Teams = game:GetService("Teams")

ReplicatedStorage.Remotes.JoinTeam.OnServerEvent:Connect(function(player: Player, teamName: unknown)
	if typeof(teamName) ~= "string" then
		return
	end
	local team = Teams:FindFirstChild(teamName)
	if team and team:IsA("Team") then
		player.Team = team
	end
end)

Fixed example

Fixed
local GroupService = game:GetService("GroupService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Teams = game:GetService("Teams")

local groupId = 1234567
local guardRoleIds = { [9876543] = true, [9876544] = true }

local function isGuard(player: Player): boolean
	local ok, info = pcall(GroupService.GetRolesInGroupAsync, GroupService, player.UserId, groupId)
	if not ok or typeof(info) ~= "table" then
		return false
	end
	for _, role in info.Roles do
		if guardRoleIds[role.Id] then
			return true
		end
	end
	return false
end

local rules: { [string]: (Player) -> boolean } = {
	Visitors = function()
		return true
	end,
	Guards = isGuard,
}

ReplicatedStorage.Remotes.JoinTeam.OnServerEvent:Connect(function(player: Player, teamName: unknown)
	if typeof(teamName) ~= "string" then
		return
	end
	local rule = rules[teamName]
	local team = Teams:FindFirstChild(teamName)
	if rule and team and team:IsA("Team") and rule(player) then
		player.Team = team
	end
end)

Common false positives

  • Teams with no extra powers, such as colour teams in a free-for-all or teams balanced by the server, can be open to anyone.
  • A limited team that's auto-assignable is fine when a server script moves anyone who doesn't qualify straight back out on PlayerAdded.
  • Team-only doors, tools and commands that check player.Team on the server are the right way to use teams. Report them only when joining the team itself isn't checked.