Lock down your server events before a cheater finds them
Most "money hacks" are not hacks at all, just a cheat calling a server event your script trusted too much. Five habits that close the most common holes in FiveM resources.
Most "money hacks" are not hacks at all, just a cheat calling a server event your script trusted too much. Five habits that close the most common holes in FiveM resources.
When a cheater gives themselves a million in cash or spawns rare items, it is rarely because they broke anything clever. Far more often, a resource registered a server event that does exactly that, and trusted whatever the client sent. Cheat menus list these events by name and fire them with their own arguments. An anti-cheat can catch a lot of this, but the cheapest fix is not to leave the door open in the first place.
The client should ask for an action; the server should decide the result.
-- Risky: the client chooses the payout
RegisterNetEvent('jobs:finishDelivery', function(amount)
local src = source
AddMoney(src, amount)
end)
-- Better: the server knows the price
local DELIVERY_PAY = 450
RegisterNetEvent('jobs:finishDelivery', function()
local src = source
if not IsOnDelivery(src) then return end
EndDelivery(src)
AddMoney(src, DELIVERY_PAY)
end)
Before rewarding anything, confirm the state the reward depends on: is the player near the drop-off point, do they actually have the job, did they start the task, has enough time passed? Keep that state on the server. If the client is the only one who knows a task was started, a cheat can claim it was finished.
local DROP = vector3(215.8, -810.1, 30.7)
local ped = GetPlayerPed(src)
if #(GetEntityCoords(ped) - DROP) > 10.0 then return end
source, never a player ID from the argumentsAn event that takes a target player ID as an argument lets a cheat act on anyone. When the action is about the caller, use source. When it really is about another player (giving an item, sending a bill), check that the two are close to each other and that the caller is allowed to do it.
A legitimate player finishes a delivery every few minutes, not ten times a second. A small per-player cooldown on rewarding events stops loops instantly and gives you a clear signal to log.
local last = {}
local function cooldown(src, seconds)
local now = os.time()
if last[src] and now - last[src] < seconds then return false end
last[src] = now
return true
end
AddEventHandler('playerDropped', function() last[source] = nil end)
Old test commands, admin shortcuts left from development, "give item" events from a script you replaced: each one is a free gift to a cheat menu. Search your resources for RegisterNetEvent and ask, for every result, which client code actually calls it.
TruffAC watches for events fired by resources that do not exist, for events called far more often than a human could, and for the patterns cheat menus use, and records evidence when it bans. That catches the attempt. Tight server code makes sure the attempt does not work even before the ban lands.