Protect your game from exploiters and implement security best practices.
Never trust the client - always validate on the server.
local MAX_SPEED = 100 -- studs per second
local lastPositions = {}
local function validateMovement(player, newPosition)
local character = player.Character
if not character then return false end
local lastData = lastPositions[player.UserId]
if lastData then
local distance = (newPosition - lastData.position).Magnitude
local timeDiff = tick() - lastData.time
local speed = distance / timeDiff
-- Check if speed is impossible
if speed > MAX_SPEED then
warn(player.Name .. " is moving too fast: " .. speed)
return false
end
end
lastPositions[player.UserId] = {
position = newPosition,
time = tick()
}
return true
end
moveRemote.OnServerEvent:Connect(function(player, position)
if typeof(position) ~= "Vector3" then return end
if not validateMovement(player, position) then return end
-- Apply movement
player.Character.HumanoidRootPart.Position = position
end)
Validate player movement to prevent teleportation hacks.
local ShopItems = {
["sword"] = {price = 100, name = "Sword"},
["potion"] = {price = 50, name = "Potion"}
}
purchaseRemote.OnServerEvent:Connect(function(player, itemId)
-- Type validation
if typeof(itemId) ~= "string" then
warn(player.Name .. " sent invalid item ID")
return
end
-- Item exists validation
local item = ShopItems[itemId]
if not item then
warn(player.Name .. " tried to buy non-existent item")
return
end
-- Currency validation
local coins = player.leaderstats.Coins.Value
if coins < item.price then
-- Not enough money
return
end
-- Price validation (check if price wasn't modified)
if item.price ~= ShopItems[itemId].price then
warn("Price mismatch detected!")
return
end
-- All checks passed - process purchase
player.leaderstats.Coins.Value = coins - item.price
giveItem(player, itemId)
end)
Validate every aspect of a purchase to prevent exploits.
Implement checks to detect impossible game states.
local function sanitizeValue(value, min, max, default)
if typeof(value) ~= "number" then
return default
end
if value < min or value > max then
return default
end
return value
end
damageRemote.OnServerEvent:Connect(function(player, targetPlayer, damage)
-- Sanitize damage value
damage = sanitizeValue(damage, 0, 100, 0)
if damage == 0 then
warn(player.Name .. " sent invalid damage")
return
end
-- Apply damage
local humanoid = targetPlayer.Character:FindFirstChild("Humanoid")
if humanoid then
humanoid:TakeDamage(damage)
end
end)
Sanitize all numeric values to prevent impossible values.
local function canUseAbility(player, abilityName)
-- Check if player is alive
local character = player.Character
if not character then return false end
local humanoid = character:FindFirstChild("Humanoid")
if not humanoid or humanoid.Health <= 0 then
return false, "Player is dead"
end
-- Check if player owns the ability
if not playerAbilities[player.UserId][abilityName] then
warn(player.Name .. " tried to use ability they don't own")
return false, "Ability not owned"
end
-- Check cooldown
if isOnCooldown(player, abilityName) then
return false, "Ability on cooldown"
end
-- Check mana/resources
local cost = AbilityData[abilityName].cost
if player.Stats.Mana.Value < cost then
return false, "Not enough mana"
end
return true
end
abilityRemote.OnServerEvent:Connect(function(player, abilityName)
local canUse, reason = canUseAbility(player, abilityName)
if not canUse then
print("Ability blocked: " .. reason)
return
end
-- Execute ability
executeAbility(player, abilityName)
end)
Check all prerequisites before allowing actions.
Detect and handle exploiters.
local suspiciousActivity = {}
local function reportSuspiciousActivity(player, reason)
local userId = player.UserId
if not suspiciousActivity[userId] then
suspiciousActivity[userId] = {
count = 0,
reasons = {}
}
end
local activity = suspiciousActivity[userId]
activity.count = activity.count + 1
table.insert(activity.reasons, {
reason = reason,
time = tick()
})
-- Log to console
warn(string.format("[SECURITY] %s: %s (Count: %d)",
player.Name, reason, activity.count))
-- Automatic actions
if activity.count >= 5 then
-- Kick player
player:Kick("Suspicious activity detected")
elseif activity.count >= 3 then
-- Warn player
warnPlayer(player, "Stop exploiting or you will be kicked")
end
end
-- Example usage
if not validateMovement(player, position) then
reportSuspiciousActivity(player, "Invalid movement detected")
return
end
Track suspicious activity and take action against repeated offenders.
Create a function that validates damage values.
local function validateDamage(player, damage, maxDamage)
-- Validate the damage value
end
local function validateDamage(player, damage, maxDamage)
-- Type check
if typeof(damage) ~= "number" then
warn(player.Name .. " sent non-number damage")
return false
end
-- Range check
if damage < 0 or damage > maxDamage then
warn(player.Name .. " sent invalid damage: " .. damage)
return false
end
-- Check for exact values (suspicious)
if damage == maxDamage and math.random() < 0.01 then
-- Very rare to hit exactly max damage every time
reportSuspiciousActivity(player, "Always hitting max damage")
end
return true
end
Continue your learning journey