Security Tactics and Cheat Mitigation Docs Update!

Hi Creators,

Today, we’re excited to announce a major update to our Security Tactics and Cheat Mitigation documentation, live now!

You’ve told us about knowledge gaps and areas where our security guidance needed clarity. This comprehensive rewrite addresses those concerns with core principles and flexible strategies to secure your game against common attack vectors.

This is a comprehensive resource, covering everything from foundational principles like “Never Trust the Client” to more advanced topics like:

  • Reducing the value of exploits through defensive game design
  • Securing your universe structure and keeping server logic confidential
  • Using behavioral patterns and decoy systems to detect exploiters

Since these principles are foundational to game security, we recommend all developers read this guide thoroughly.

We’ll continue updating this documentation as new attack vectors emerge and platform features evolve, including the upcoming server authority release.

We’d love your feedback! Let us know if you use security patterns we haven’t covered or if any sections need clarification.

Thank you!

189 Likes

This topic was automatically opened after 10 minutes.

Remember in 2022 or '23 when you said “developers shouldn’t have to worry about exploiters” again. Where’s that energy today?

Alt detection basically doesn’t work, several UBs that developers were using to detect exploits were removed, and there’s been reports that bots aren’t even being banned by Roblox after being detected.

Server authority is a step in the right direction, and this is a pretty good guide on its own, but theres still issues that need to be addressed from Roblox’s side.

114 Likes

This is a good update! It would help using tactics to be safe! Be safe guys :grinning_face:

7 Likes

This is a fantastic and massive document that covers SO MUCH information so many people previously had to find out the hard way to learn.

Huge thank you to the team and may the future of Roblox experiences be developed with security in mind!

9 Likes

Beautifully written. I believe everyone should give this documentation a good read. It takes consideration of many elements and points we have discussed on this forum many times before.

I expect to see an update when the Server Authority feature is fully released, however. Or a link to it to further direct developers into right solutions.

6 Likes

Great documentation! However, in my opinion, one major bad practice seems to not be mentioned: relying on math.random (and/or Random.new) for rewarding players – Developers don’t seem to be aware of PCG32’s cryptographic weaknesses.

Speaking of which, when will a native CSPRNG be implemented? While RbxCryptography can currently fulfill such tasks, it’d be nice to see (a) native CSPRNG API(s).

Aside from that, it looks polished and complete, great job to whoever wrote it.

PS: While reading the documentation, I obviously stumbled upon the decompiler section. Was this an example of what decompiler output can look like, or did you use a real decompiler?

21 Likes

Nice, these are some things gnome code covered a while ago. But good to see a up to date page.

7 Likes

It would be valuable to have a section and value validation function for invalid UTF-8 strings that can cause rollback bugs when you attempt to save them in a DataStore (especially dangerous in games with trading)

local function IsValidUTF8(s: string): boolean
    return utf8.len(s) ~= nil
end

IsValidUTF8("\x80") --> false
24 Likes

Well at least they’re indirectly admitting Byfron does literally nothing and alt detection doesn’t work. It’s better than ignoring the fluro pink elephant in this miniscule room

5 Likes

Alt detection basically doesn’t work

It doesnt work at all. Ive banned people just to have them make a new account and rejoin my server within the minute. Reporting them for the terrible things they say doesn’t work.

We used to have a way of detecting these ban evaders, to an extent, until Roblox patched it to stop us.

Why does Roblox not want us banning people?

13 Likes

a few typos / mistakes:


aside from this, though, it’s a pretty good writeup. it is offsetting some of the work to game developers that should really be covered already by roblox, however.

oh and please please give us an actual way to test our game, the official advice should NOT be to just install an exploit and use it on your game

9 Likes

Most exploits simply allow the user to execute client-side scripts because that’s the only way they can meaningfully interact with the game’s systems, i.e. firing remotes. You can do this yourself from studio’s command bar without an exploit installed, you just won’t have access to some protected functions. There is a way to bypass that too using cheat engine and editing studio’s memory if you really want to try something bizarre (I’m not sure if you can still do this though, last time I tried was ages ago), but you shouldn’t need this at all for the mostpart.

4 Likes

This is extremely in-depth and has a lot of detail and things that I didn’t know before (e.g NaN numbers being dangerous). This is great work, thanks a lot for this. It’ll help a lot of devs.

2 Likes

Can you explain why exploiters are being let off with warnings and 1-day bans instead of being terminated upon detection? Why are the platform’s top games, such as Steal a Brainrot and Rivals, still forced to use custom-built lua client-sided anticheat despite Hyperion existing? Why has Roblox posted over 4 topics now stating how they’re totally going to taking cheating seriously, yet continue to issue limp-wristed ineffective punishments?

What ever happened to the anti-cheat roadmap, in which it was stated that we would receive “more ways to identify and block cheaters using Byfron’s technology”. Where is that tooling?

When top developers are still all writing majority of anti-cheat code themselves due to the ineffectiveness of Hyperion, what are those millions of dollars per year being spent on Roblox anti-cheat going towards exactly?

If this is a platform issue, where is the platform-wide action in response? Obviously there is no excusing client-authoritative design and every developer should be writing secure code as there is no such thing as perfect anti-cheat, but why is Roblox refusing to clean up the platform? You have the technology to discourage it through serious punishments, yet you refuse to.

13 Likes

A lot better than the old versions, but if it were up to me, I’d also include the fact that TeleportData is sent by the client, therefore letting the client edit it freely. I’ve seen many devs send player data through it, and wonder how exploiters have an infinite amount of currency.

There’s also the fact that humanoid animations currently replicate, allowing exploiters to play any animation they want; they are also able to spam the .AnimationPlayed connection, which, depending on the game, can cause lag or crash it.

While it is mentioned elsewhere, you should include the fact that InvokeClient can yield indefinitely if an exploiter returns task.wait(9e9) or similar. And, Roblox secrets should be included for security for api keys and the like. Maybe add a note that this isn’t to store values securely on the client.

On top of this, there are currently internal signals (I won’t say what) that allow exploiters to respawn faster than RespawnTime or stay dead longer than RespawnTIme. And I’m pretty sure there’s some method to gain ownership of accessories when the player dies, allowing for re-animation exploits.

Snippet from my old ac

function CharacterHandler:Add(Player, Character)
	local Head = Character:FindFirstChild("Head")
	local Humanoid, HRP = Character:FindFirstChild("Humanoid"), Character:FindFirstChild("HumanoidRootPart")
	if not HRP or not Humanoid then
		return
	end

	local Animator = Humanoid:FindFirstChild("Animator")
	local Data = self.PlayerData[Player]

	if self.LastDeaths[Player] and os.clock() - self.LastDeaths[Player] < (Players.RespawnTime - 0.5) then
		return self:TakeAction(Data, "Fast Death", function()
			Player:Kick("Fast Death")
		end)
	end

	table.insert(Data.Connections, Player.CharacterAppearanceLoaded:Connect(function()
		local Accessories = Humanoid:GetAccessories()
		if #Accessories > 50 then
			return self:TakeAction(Data, "Hat Crash", function()
				Player:Kick("Hat Crash")
			end)
		end

		for _, Accessory in Accessories do
			if Accessory:FindFirstChildWhichIsA("Script", true) then
				return self:TakeAction(Data, "Hat Backdoor", function()
					Player:Kick("Hat Backdoor")
				end)
			end

			for _, Vector in {"X", "Y", "Z"} do
				local Handle = Accessory:FindFirstChild("Handle")
				if Handle and Handle.Size[Vector] >= 5 then
					Accessory:Destroy()
				end
			end
		end
	end))

	table.insert(Data.Connections, Animator.AnimationPlayed:Connect(function(AnimationTrack)
		Data.Tolerance.AnimationPlayed += 1

		if os.clock() - Data.Timing.LastAnimation >= 1 then
			if Data.Tolerance.AnimationPlayed >= 50 then
				self:TakeAction(Data, "Animation Spam", function()
					Player:Kick("Animation Spam")
				end)
			end
			Data.Tolerance.AnimationPlayed = 0
			Data.Timing.LastAnimation = os.clock()
		end

		local AnimationId = string.match(AnimationTrack.Animation.AnimationId, "%d+")
		if not self.Whitelist[AnimationId] then
			self:TakeAction(Data, "Animation", function()
				Player:Kick("Animation")
			end)
		end

		if AnimationTrack.Speed >= 10 then
			self:TakeAction(Data, "Animation Speed", function()
				self:BreakJoints(Data)
			end)
		end
	end))

	table.insert(Data.Connections, Humanoid.StateChanged:Connect(function(Old, New)
		Data.Tolerance.StateChanges += 1

		if os.clock() - Data.Timing.LastState >= 1 then
			if Data.Tolerance.StateChanges >= 50 then
				self:TakeAction(Data, "State Spam", function()
					Player:Kick("State Spam")
				end)
			end

			Data.Tolerance.StateChanges = 0
			Data.Timing.LastState = os.clock()
		end

		if Data and Old == Enum.HumanoidStateType.Dead and New ~= Enum.HumanoidStateType.Dead then
			self:TakeAction(Data, "God", function()
				self:BreakJoints(Data)
			end)

		elseif Old ~= Enum.HumanoidStateType.Dead and New == Enum.HumanoidStateType.Dead then
			if Data and Players.CharacterAutoLoads then
				task.delay(Players.RespawnTime + 0.5, function()
					if Player.Character == Character then
						self:TakeAction(Data, "Respawn Time Exceeded", function()
							Player:Kick("Respawn Time Exceeded")
						end)
					end
				end)
			end
		end
	end))

	table.insert(Data.Connections, Humanoid.PlatformStanding:Connect(function()
		self:TakeAction(Data, "Platform Standing", function()
			Player:Kick("Humanoid Platform Standing")
		end)
	end))

	table.insert(Data.Connections, Humanoid.AncestryChanged:Connect(function(_, Parent)
		if game:IsAncestorOf(Character) then
			if Character.PrimaryPart and Character:IsAncestorOf(Character.PrimaryPart) then
				if not Parent or not game:IsAncestorOf(Humanoid) then
					self:TakeAction(Data, "God", function()
						self:BreakJoints(Data)
					end)
				end
			end
		end
	end))

	table.insert(Data.Connections, Character.ChildAdded:Connect(function(Child)
		if Child:IsA("BasePart") then 
			Child.CollisionGroup = "Characters"

		elseif Child:IsA("Tool") then
			local Count = 0
			for _, Tool in Character:GetChildren() do
				if Tool:IsA("Tool") then
					Count += 1
				end
			end

			if Count > 1 then
				self:TakeAction(Data, "Multiple Tools", function()
					self:BreakJoints(Data)
				end)
			end
		end
	end))

	table.insert(Data.Connections, Humanoid.Died:Connect(function()
		task.delay(1, function()
			if Player.Character == Character then
				for _, Accessory in Humanoid:GetAccessories() do 
					Accessory:Destroy()
				end
			end
		end)

		for _, Descendant in Character:GetDescendants() do
			if Descendant:IsA("BasePart") then
				if Descendant:CanSetNetworkOwnership() then
					Descendant:SetNetworkOwner(nil)
				end
				Descendant.AssemblyLinearVelocity = Vector3.zero
			elseif Descendant:IsA("Script") then -- Health script, doesnt have a .died check so it will regen health with inf death making you unkillable
				Descendant:Destroy()
			end
		end
		self.LastDeaths[Player] = os.clock()
	end))
end
6 Likes

so you want us to do the whole banning exploiters work for you?

8 Likes

About the upcoming server validation feature, how is it going to know the speed of vehicles and stuff like that controlled by players?

1 Like

Not to mention that the invasive anti-cheat killed off things like native Linux support yet the anti-cheat barely works. I see kids with iOS apps exploiting in games. Not sure why basic anti-cheat like flying isn’t enabled by default then optionally disabled by the developer.

3 Likes

Hey everyone, I wanted to thank you all for the ample detailed feedback. Please keep it coming. We will incorporate your responses into future iterations of this guide.

To be clear, we still take full responsibility for anti-cheat on the platform. This documentation does not serve to shift the burden of anti-cheat onto developers. Instead, our goal with this update is to help inform creators on the capabilities of exploiters and incorporate that knowledge into design strategy. Ultimately, when you all have to put in extra hours to fight cheaters, we still view that as a failure on our part.

We welcome any and all feedback regarding our anti-cheat strategy and product offerings. We understand many of you are frustrated. We hear you. The more specific you are in your feedback, the better.

Thanks!

21 Likes