Most economy exploits on a FiveM server come down to one mistake: a server event handler that trusted whatever the client sent it. Server-side event validation fixes that in your own code. A client-side anticheat helps, but it cannot fix a handler that pays out to anyone who asks.
Any connected client can call a registered net event through TriggerServerEvent, with any arguments it wants. Cfx.re's own guide, Secure Your Events, says cheats can trigger events in any context. The danger starts when a handler treats those arguments as if a normal client sent them.
The exploit, in two lines
This is the kind of handler that gets servers wiped:
RegisterNetEvent('shop:buy', function(itemId, price)
local src = source
-- Trusts the client to send the right price.
exports.ox_inventory:AddItem(src, itemId, 1)
Player(src).state.cash = Player(src).state.cash - price
end)A cheater calls TriggerServerEvent('shop:buy', 'weapon_combatpdw', 0) and walks off with a free weapon. A negative price pays them for it instead. No aimbot is involved, only a one-line script that any Lua executor can run.
The fix is to validate on the server:
RegisterNetEvent('shop:buy', function(itemId)
local src = source
-- The client only names the item. The price comes from our own catalog.
local item = ITEM_CATALOG[itemId]
if not item then return end -- unknown item id
if not isPlayerNearShop(src) then return end -- not at a shop
local cash = Player(src).state.cash or 0
if cash < item.price then return end -- can't afford
exports.ox_inventory:AddItem(src, itemId, 1)
Player(src).state.cash = cash - item.price
end)The handler now reads the price from a catalog the server controls, checks that the player is near a shop, and confirms they can pay. Nothing the client sends is trusted on its own.
Why a client-side anticheat is not enough
A client-side anticheat catches aimbots, mod menus and Lua executors before they fire an event, and you should run one. It works by spotting the cheat, and no anticheat spots every cheat on the day it ships. A validated handler does not depend on spotting anything. It refuses a bad request from any client, and the next cheat release does not change that.
What "validate everything" means in practice
Run every server event handler through this checklist:
- Identity: never take a player ID from the client. Use
source. - Authority: read the state the player should have (job, location, inventory) from your own server data, never from the event arguments.
- Bounds: check that any number the client sends sits within sane limits. A money amount of 999,999,999 is not a purchase, and neither is a negative one.
- Rate: the same player calling
shop:buy200 times a second is a script. Throttle handlers that are cheap to spam. - Catalog lookups: when the client sends an ID, look it up in a server-side catalog and take everything else (price, weight, properties) from there.
How Raven handles event protection
An anticheat lowers the risk on handlers you have not hardened yet. Raven's Server Event Protections ships on and set to ban. It covers the events of every resource Raven is installed into, refuses events a player should not fire, and names the event and its resource on each hit. A client-side version ships off.
When one of your own scripts trips it, you whitelist that event, or the whole resource, in Protection Rules. Raven Mind suggests a fix for each hit, including trusting a whole resource when the same one keeps tripping it. It never adds an event whitelist without an operator. The Server Event Protections docs cover how to whitelist without opening a hole. Raven does not replace the handler checks above.