How to stop players teleporting to places they haven't unlocked
A remote that teleports to any place id or access code the client sends skips paywalls and private matches. How to use server-side destination lists.
What it looks like
A menu, portal or party system lets the client ask to be teleported, and the server teleports them wherever the remote says: a place id, a reserved server access code or a server instance id.
Luau
remotes.Travel.OnServerEvent:Connect(function(player, placeId) TeleportService:TeleportAsync(placeId, { player }) end)
How to detect it
- Find every server call to
TeleportService:TeleportAsyncand the olderTeleport,TeleportToPlaceInstance,TeleportToPrivateServerandTeleportPartyAsync. Trace each place id, access code and instance id back to its source. TeleportAsynccan only be called from the server, and Roblox's teleport guide says that is to reduce client-side exploits. A server that teleports to whatever the client asks gives that protection away.- A place id from the client must be checked against the game's own list of places, and against what the player has unlocked: a paid world, a level requirement, a staff place.
TeleportOptions.ReservedServerAccessCodeis what lets a player into a reserved server, such as a match, a party's private session or a staff test server. An access code sent by the client lets them join any reserved server whose code they've seen or guessed. Keep codes on the server, in a server table or memory store, keyed by something the server checks.TeleportOptions.ServerInstanceIdfrom the client lets players pick a specific public server. That's usually fine, as in a server browser, but check whether it lets them join a server they've been removed from or a match already in progress.- Players taken along in the
playerslist must be checked too. A client that names other players in a party teleport can move them without asking.
What an exploiter could do
They teleport into paid or locked places without paying or unlocking them, join private matches and staff servers with codes copied from other players, or drag other players into places they didn't choose. Content in those places replicates as soon as they arrive.
How to fix it
- Let the client send a key from a server-side table, such as
"Desert", and look up the place id on the server. Check the player has unlocked it. - Create reserved servers on the server and keep their access codes there. Teleport players into them based on server-side state, such as their party or match.
- Only teleport other players who have agreed, for example as members of a party the server tracks.
Vulnerable example
Vulnerable
local ReplicatedStorage = game:GetService("ReplicatedStorage") local TeleportService = game:GetService("TeleportService") ReplicatedStorage.Remotes.TravelTo.OnServerEvent:Connect(function(player: Player, placeId: unknown, code: unknown) if typeof(placeId) ~= "number" then return end local options = Instance.new("TeleportOptions") if typeof(code) == "string" then options.ReservedServerAccessCode = code end pcall(TeleportService.TeleportAsync, TeleportService, placeId, { player }, options) end)
Fixed example
Fixed
local ReplicatedStorage = game:GetService("ReplicatedStorage") local TeleportService = game:GetService("TeleportService") local PlayerData = require(script.Parent.PlayerData) local worlds: { [string]: { placeId: number, level: number } } = { Meadow = { placeId = 9100401, level = 1 }, Desert = { placeId = 9100402, level = 10 }, } ReplicatedStorage.Remotes.TravelTo.OnServerEvent:Connect(function(player: Player, name: unknown) if typeof(name) ~= "string" then return end local world = worlds[name] local profile = PlayerData.get(player) if not world or not profile or profile.Level < world.level then return end pcall(TeleportService.TeleportAsync, TeleportService, world.placeId, { player }) end)
Common false positives
- Teleporting to a place id the server picked from its own table, even when the client chooses which entry, is fine if every entry is open to that player.
- A server browser that lets players pick a public
ServerInstanceIdis normal, as long as nothing makes some servers off-limits. - Teleports the server starts on its own, such as moving a whole lobby into a match, take no client input. Judge them by Teleport or launch data trusted for anything of value on the receiving side.