GM Market — Premium GMod & FiveM Scripts
Roblox Guide 🇺🇸 English

Roblox Server-Side Anti-Cheat: Stop Speed & Fly Hacks

>*Muzan Moderator
@>*Muzan · Moderator ·
522 views 0 replies

TL;DR

There's no silver-bullet library. Every "drop-in anti-cheat" will be bypassed by a halfway-decent exploiter quickly. What actually works is understanding why cheats are hard to detect server-side, then layering targeted sanity checks that accumulate evidence before acting. This guide is that checklist.


Why Server-Side Detection Is Hard

Before writing a single line of detection code, you need to understand the core problem: by default, the client owns its own character's physics. The server trusts the position data the client sends.

As the Roblox Wiki on replication filtering explains, filtering works by discarding property changes, but physics replication is handled by internal engine code — not scripts. This is why WalkSpeed exploits can speed up a cheater's character on the client without the property changing detectably on the server.

As Quenty's network ownership breakdown notes, if a player has network ownership over their character, they can send bad positional data — and Roblox does not verify physics calculations.

The consequence: You cannot simply read HumanoidRootPart.Position and trust it. You must compare it over time against what is physically plausible.


The Core Strategy: Plausibility, Not Property Checks

The classic mistake is checking Humanoid.WalkSpeed > 16. An exploiter can hook the speed value and mask it — the property looks fine on the server while the character moves at 200 studs/sec.

The real signal is movement delta over time.

Every polling interval, compare:

  • Where was the player last tick?
  • Where are they now?
  • How much time elapsed?
  • What is the maximum plausible distance they could cover?

If actual_distance >> max_plausible_distance, you have a flag.

-- Simple plausibility helper
local function getMaxPlausibleDistance(humanoid, dt, tolerance)
    tolerance = tolerance or 1.8
    return humanoid.WalkSpeed * dt * tolerance
end

Always use your server-authoritative WalkSpeed value — the one your game assigned — not a value you read back from the client's character.


Checklist: What to Detect and How

✅ 1. Speed Hacks — Track horizontal displacement per tick

local lastPos = {}

local function watchPlayer(player, character)
    local hrp = character:WaitForChild("HumanoidRootPart")
    local humanoid = character:WaitForChild("Humanoid")
    lastPos[player] = hrp.Position

    task.spawn(function()
        while character.Parent do
            task.wait(0.2)
            local curr = hrp.Position
            local prev = lastPos[player]
            if prev then
                local hDist = Vector3.new(curr.X - prev.X, 0, curr.Z - prev.Z).Magnitude
                local maxAllowed = humanoid.WalkSpeed * 0.2 * 2.0  -- 2× tolerance
                if hDist > maxAllowed then
                    -- add strike, never instant-kick on first flag
                    warn(player.Name .. " speed flag | dist=" .. math.round(hDist))
                end
            end
            lastPos[player] = curr
        end
    end)
end

False positive killers:

  • Use a 1.5–2× tolerance multiplier — lag causes legitimate position spikes.
  • Skip checks for ~1 second after any server-initiated PivotTo() / respawn.
  • Disable checks while the player is in a vehicle (track a server-side bool).

✅ 2. Fly Hacks — Sustained airtime with no downward velocity

Fly cheats keep the character permanently airborne. Check Humanoid.FloorMaterial: if it returns Enum.Material.Air for too many consecutive ticks and the character isn't actually falling, it's suspicious.

local airTicks = {}

task.spawn(function()
    while true do
        task.wait(0.25)
        for _, player in ipairs(game.Players:GetPlayers()) do
            local char = player.Character
            if not char then continue end
            local humanoid = char:FindFirstChildOfClass("Humanoid")
            local hrp = char:FindFirstChild("HumanoidRootPart")
            if not humanoid or not hrp then continue end

            if humanoid.FloorMaterial ~= Enum.Material.Air then
                airTicks[player] = 0
            else
                airTicks[player] = (airTicks[player] or 0) + 1
                -- 3 seconds sustained air = suspicious
                if airTicks[player] >= 12 then
                    local vy = hrp.AssemblyLinearVelocity.Y
                    if vy > -5 then  -- not actually falling
                        warn(player.Name .. " fly flag")
                        airTicks[player] = 0
                    end
                end
            end
        end
    end
end)

Pitfalls: Ladders, moving platforms, and long-jump mechanics all produce Air floor material. Tune the tick threshold to your game — a flat RP map can use 8 ticks; a parkour game may need 20+.


✅ 3. Teleport Hacks — Single-tick displacement above any plausible max

If a player moves 500 studs in 0.1 seconds, no amount of lag explains that. But your own game's teleports will trigger this check too — a critical DevForum-documented pitfall. Fix it with a server-side exemption flag:

local teleportExempt = {}

local function serverTeleportPlayer(player, destination)
    teleportExempt[player] = tick()   -- mark as exempt for 1 second
    if player.Character then
        player.Character:PivotTo(destination)
    end
end

local function isTeleportExempt(player)
    local t = teleportExempt[player]
    return t and (tick() - t) < 1.0
end

Hard threshold example: with WalkSpeed = 16 and a 0.1 s tick, max plausible travel is ~32 studs with 2× tolerance. Anything above 80–100 studs per tick is a hard flag regardless of ping.


✅ 4. WalkSpeed Tampering — Cross-check via Humanoid.Running

Even if the property is masked, the Humanoid.Running event fires with the actual movement speed — a cheap secondary signal:

humanoid.Running:Connect(function(speed)
    if speed > humanoid.WalkSpeed + 8 then
        warn(player.Name .. " Running mismatch: " .. speed)
    end
end)

✅ 5. Gravity & NoClip

  • Gravity: Loop-check workspace.Gravity server-side. If it changes from your baseline (default 196.2), reset it immediately.
  • NoClip: Cast a workspace:Raycast() between the player's previous and current positions. If the ray hits a solid part the player passed through, flag it.

The Strike System: Never Instant-Kick

This is the most critical architectural decision. Network lag, ping spikes, and your own game mechanics will produce false positives. Experienced developers on the DevForum consistently note that movement checks shouldn't result in bans due to network unreliability alone.

Use a weighted strike accumulator with decay:

EventStrikes
Minor speed flag (1 tick)+1
Large/sustained speed flag+3
Fly flag (12+ ticks)+4
Hard teleport (100+ studs/tick)+5
WalkSpeed mismatch+2
  • 10 strikes → log to Discord webhook
  • 20 strikes → kick with message
  • Repeat offenders across sessionsDataStoreService ban

Strikes should decay (e.g. −1 every 30 s of clean movement) so a one-off lag spike doesn't punish legit players.


Logging

Every flag should record: UserId, DisplayName, flag type, server position, and timestamp. Route this to a Discord webhook and persist repeat-offender counts via DataStoreService.


The Nuclear Option: Server-Authoritative Character Controllers

For competitive or economy-critical games, sanity checks are a cat-and-mouse game. The real solution is a server-authoritative character controller like Chickynoid.

Chickynoid trusts nothing from the client except input directions — the server runs the authoritative physics simulation and corrects the client on disagreement. Players literally cannot move-cheat because the server's character state is ground truth. The trade-off is serious engineering effort: it's not a drop-in replacement for Humanoid-based characters.


Common Pitfalls at a Glance

  • Checking WalkSpeed property alone — it can be masked client-side
  • No ping tolerance — lag spikes trigger legit player kicks
  • Forgetting to exempt server-side teleports (respawn, cutscenes)
  • Polling too frequently — 0.1–0.25 s intervals are sufficient
  • Not accounting for vehicles/dashes — track game states server-side
  • Instant-kick on first flag — always use a strike accumulator
  • No logging — you need data to tune thresholds

FAQ

Q: Can SetNetworkOwner(nil) stop character physics cheats? Not for the player's own character — Roblox automatically reassigns ownership back. It works well for world props and NPC parts, but not for the character itself.

Q: Is a client-side anti-cheat worth adding? It's a deterrent for casual script kiddies but provides zero security against any real executor. Server-side is your only reliable layer.

Q: What about Roblox's built-in anti-cheat? The platform's system targets executor detection and ToS violations — not your custom game mechanics like a special WalkSpeed buff or teleport ability. Game-logic integrity is on you.


Building anti-cheat is iterative — your first version will have false positives. Log everything, watch your Discord webhook, and tune thresholds week by week. You can browse community scripts on GM Market as a reference baseline, but always audit and tune anything you use. Good luck. 🛡️

0

0 Replies

No replies yet — be the first to respond.