Hello. I have a script that, when teleporting a group of players to a ReserveServer instance, passes along a set of teleport data:
local function teleportGroup(players: table, info: table)
local teleportData = {}
if (#players == 0) then return end
for i,v in pairs(players) do
teleportData["GlobalInfo"] = info
teleportData["Players"] = {}
teleportData["Players"][v.UserId] = {}
teleportData["Players"][v.UserId]["Loadout"] = {}
teleportData["Players"][v.UserId]["Level"] = v:WaitForChild("info"):WaitForChild("Level").Value
for a,b in pairs(v:WaitForChild("info"):WaitForChild("Loadout"):GetChildren()) do
if b.Value ~= "None" then
teleportData["Players"][v.UserId]["Loadout"][tonumber(b.Name)] = b.Value
else
teleportData["Players"][v.UserId]["Loadout"][tonumber(b.Name)] = "None"
end
end
end
print(teleportData)
local reserved = TeleportService:ReserveServer(--[[ REDACTED]])
TeleportService:TeleportToPrivateServer(--[[REDACTED]], reserved, players, "SpawnLocation", teleportData)
end
which is then interpreted by the new reserved server instance like so:
players.PlayerAdded:Connect(function(player)
local teleportData = player:GetJoinData().TeleportData
if not player:GetJoinData().SourcePlaceId or player:GetJoinData().SourcePlaceId ~= --[[REDACTED]] then
teleportService:TeleportAsync(--[[REDACTED]], {player}) end
if teleportData then -- if they got teleported with data
print(player:GetJoinData().SourcePlaceId)
printTableRecursive(teleportData)
game.ReplicatedStorage.Remotes.getData:Fire(player, teleportData)
game.ReplicatedStorage.Remotes.updateUI:FireClient(player)
else
teleportService:TeleportAsync(--[[REDACTED]], {player})
end
end)
My question is can an exploiter modify any of this? I have read on the Creator Hub’s documentation that it is spoofable, but on the other hand there seem to be threads on the devforum saying otherwise.
From what im personally aware, they cant edit it once the teleport has been created, but they can create their own teleport with fake teleport data.
Its why its risky to do data transfers with teleport data, from game to game, is because a player can just use an exploit to create false teleport data and teleport with it.
However, considering that byfron now exists, and basically every good exploit is gone (like synapse), you probably dont need to worry.
There will soon be ways to bypass Byfron, and I’m trying to futureproof my code as much as I can.
What would be other more secure ways to do this sort of stuff, then?
You can create a glitch website and send the data thru that, store it temporarily, then when you get teleported, retrieve it from glitch. Id recommend doing this on the server however for sure.
You can also use a rasperry pi and port forward if you have one, but depending on what your doing that is a bad workaround as glitch.com does have an hour limit of 1000 per month.
Thats half true, you can send this data thru the client, and I know from personal experience that this is possible. To quote the docs for SetTeleportData:
This is a setter function for data to be passed to the destination place. On the destination place, this data can be retrieved using Player:GetJoinData() or TeleportService:GetLocalPlayerTeleportData(). (https://create.roblox.com/docs/reference/engine/classes/TeleportOptions)
I cannot remember if getLocalPlayerTeleportData returns different than getJoinData (as you can set teleport data on both client and server) but I am well aware of how it can be exploited.
There is no way a client can send or change JoinData. Only the server can teleport players between experiences so this is all up to server what data it sends. Player can only exploit it when you let the player send you the data that they want to be passed into the JoinData.
Short answer: As @BubasGaming said, TeleportData fetched from GetJoinData() on the server is secure in most aspects. I would still consider using memory store or data stores in your situation.
Long answer:
Here is what the documentation says about GetJoinData().
The client is the one who transmits teleport data. It is fair to speculate that the data is encrypted beforehand. The receiver automatically invalidates the data if it finds any signs of tampering. In that case it is shown as nil, as well as if the exploiter refuses to pass the data at all.
As you can see, there is certain security criteria in place.
However, there are two vulnerabilities to be taken into account:
An exploiter can keep the data from previous teleports intact and reuse it. The receiver only offers guarantees described in the documentation, meaning the reused data is not invalidated in the first 48 hours (opening exposure to potential duplication issues).
TeleportData is not suitable for sensitive information that ought to remain private because party teleports include shared data. An exploiter can call GetLocalPlayerTeleportData() to view the whole table.
The first issue is effectively mitigated with hashing - a fairly straightforward process if hashing libraries are used. Look into colbert2677’s solution here.
Another solution is to generate a UUID for each teleport to represents a ticket. The receiver then checks if the received ticket exists in the memory store: If it does, then it was already spent and the player should be kicked, otherwise the teleport is valid and the ticket should be stored in the memory store for a short while (let’s round the period to 50 hours).
The second point mentions a potential vulnerability, which can also be mitigated using encryption (considering the fact that teleport data doesn’t have size limits). Nevertheless, memory stores and data stores are deemed more suitable for such cases.