Basic FiveM server security without an anticheat — server.cfg hardening, anti money-dupe scripting and ban evasion (up to 2,000 players)
A free FiveM server security guide to do before you buy an anticheat: harden server.cfg (sv_entityLockdown, sv_filterRequestControl, networked sounds and phone explosions, sv_scriptHookAllowed), block the game events cheaters use to give or strip weapons and kick players out of vehicles, write economy scripts where the server decides the money so dupes stop, lock the economy before restarts, tie Discord and Rockstar license together against ban evasion, and keep logs that scale to a 2,000-player city.
The first question new server owners ask is usually "which anticheat should I buy". But most of the damage in a FiveM city does not come from cheat menus an anticheat catches. It comes from two things: server settings that let the client do anything and scripts that trust numbers sent from the player's PC. Both can be fixed today, for free, without any anticheat.
This guide covers five layers to put in place before you pay for anything. It works from a 32-slot server up to a 2,048-player city. One thing first: no server blocks 100% of cheaters. The real goal is to make cheating hard, low-reward and evidence-leaving. At 2,000 players, cheaters at just 1% means 20 online at once. If each of them can dupe money, the whole city's economy is gone within a week.
The five layers
| Layer | Stops | Tool |
|---|---|---|
| 1. Server structure | spawning vehicles/NPCs/props, taking over other players' vehicles, sound and explosion spam, ScriptHook | convars in server.cfg |
| 2. Economy | money exploits, item exploits, dupes | server-side code in your scripts |
| 3. Griefing other players | giving or stripping weapons, kicking players out of vehicles, random explosions | block_net_game_event, explosionEvent |
| 4. Identity | ban evasion, fresh accounts, duplicate accounts | playerConnecting + identifiers + tokens |
| 5. Logs and evidence | knowing what happened, who did it, and deciding fairly | txAdmin, database logs, screenshot-basic |
Layers 1 and 3 take under an hour. Layer 2 closes the most damage, and no anticheat can do it for you.
Layer 1: server.cfg — 10 minutes to close the biggest holes
sv_entityLockdown relaxed
sv_filterRequestControl 1
sv_enableNetworkedSounds false
sv_enableNetworkedPhoneExplosions false
sv_scriptHookAllowed false
sv_endpointPrivacy true
sv_entityLockdowncontrols which entities clients may create. The default isinactive(anything goes), which is exactly how cheat menus spawn vehicles, NPCs and props.relaxedblocks entities created by client-side scripts but keeps the game's own traffic and pedestrians, which suits most RP cities.strictblocks every client-created entity.- The trade-off: any script that creates vehicles or props on the client (garages, jobs, emote props, the phone in your hand) stops spawning them and must move creation to the server, for example with
CreateVehicleServerSetter. Always test on a dev server running the same resources first. If you cannot migrate everything yet, set it per routing bucket withSetRoutingBucketEntityLockdownMode.
- The trade-off: any script that creates vehicles or props on the client (garages, jobs, emote props, the phone in your hand) stops spawning them and must move creation to the server, for example with
sv_filterRequestControlblocks "control requests" on entities another player controls, which is how cheaters hijack other players' cars or drag vehicles around the map. Mode1blocks requests on occupied vehicles that have existed for more than 30 seconds and is the safest place to start. Modes2–4block more, but some mechanic, towing or carry scripts that need control of other players' entities will break, so test before moving up.sv_enableNetworkedSounds falseandsv_enableNetworkedPhoneExplosions falseclose two routes that the Cfx.re docs call out as commonly abused: server-wide sound spam and phone explosions. The second is alreadyfalseby default; set it explicitly so nobody turns it on.sv_scriptHookAllowed falsekeeps clients with ScriptHook out. It is the default too. The point is to never enable it, even when players ask.sv_endpointPrivacy truehides player IPs from the server's public data, which reduces targeted DDoS against individual players.sv_pureLevel(optional):1blocks modified game files except audio and known graphics mods,2blocks everything. Level 2 locks out players with graphics mods, so pick based on your player base.
Two things that are not convars but belong in the same pass:
- Do not set
rcon_passwordunless you use RCON, and grant commands withadd_acetogroup.adminonly. No command that everyone can use should be able to run code. - Never expose your database port to the internet, and give every admin their own txAdmin account. Never share the master account.
After editing
server.cfg, restart the whole server through txAdmin, notrestarton a resource. Some of these values are only read at startup.
Layer 2: the economy — the layer no anticheat can do for you
Every cheat menu can trigger your scripts' events directly, with any values it likes. If your sell event accepts "count" and "price" from the client, a cheater just sends 999999. Even the best anticheat cannot tell that value is wrong, because it is a legitimate event of your own script.
The common pattern that breaks:
RegisterNetEvent('fishing:sell', function(count, price)
local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.addMoney(count * price)
end)
The pattern where the server decides everything:
local SELL_POINT = vector3(-1845.0, -1195.0, 14.3)
local PRICE = 120
local COOLDOWN_MS = 2000
local busy, lastSell = {}, {}
RegisterNetEvent('fishing:sell', function()
local src = source
if economyLocked or busy[src] then return end
local now = GetGameTimer()
if lastSell[src] and now - lastSell[src] < COOLDOWN_MS then return end
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer or xPlayer.job.name ~= 'fisherman' then return end
if #(GetEntityCoords(GetPlayerPed(src)) - SELL_POINT) > 5.0 then return end
local item = xPlayer.getInventoryItem('fish')
if not item or item.count < 1 then return end
busy[src] = true
lastSell[src] = now
xPlayer.removeInventoryItem('fish', item.count)
xPlayer.addMoney(item.count * PRICE)
MySQL.insert.await('INSERT INTO economy_log (identifier, action, amount) VALUES (?, ?, ?)',
{ xPlayer.identifier, 'fishing:sell', item.count * PRICE })
busy[src] = nil
end)
AddEventHandler('playerDropped', function()
busy[source], lastSell[source] = nil, nil
end)
The rules in that code apply to every script that moves money or items:
- The client only says what it wants to do. Prices, amounts and rewards are all computed on the server.
- Re-check everything on the server, every time: distance to the point, job, inventory, cooldown. Client-side checks only make the UI nice; they stop nothing.
- Take first, give second. In the other order, stacked events get paid before the items disappear.
- Lock per player. Every handler with an
await(for example a database call) lets a second event slip in halfway. That is where most dupes come from. - Rate-limit. A real player sells a few times a minute. An event fired in a burst is the clearest signal there is.
Lock the economy before restarts
The minutes before a restart are the biggest dupe window: items handed over but not yet saved come back on both sides. txAdmin fires a warning event before each scheduled restart. Use it to stop transactions and save all players with your framework's save function.
economyLocked = false
AddEventHandler('txAdmin:events:scheduledRestart', function(eventData)
if eventData.secondsRemaining <= 60 then
economyLocked = true
end
end)
ESX Legacy Core — X3D Build (free) does this in the core and keeps an audit log of every money and item change, sent to a Discord webhook.
Minigames must be verified on the server
Lockpicking, fishing, hacking: if the client sends "passed" and the server pays out immediately, a cheater can send "passed" every second. The server has to know who started the minigame and when, reject results that arrive faster than a real player could finish, and pick the reward itself.
Before installing any new script, open its server files, find every RegisterNetEvent, and check whether a handler accepts money or amounts from the client. If it does, do not install it. More in how to check whether a FiveM script is safe and where to buy FiveM scripts safely.
Layer 3: stop griefing of other players
Cheat menus use GTA game events to act on other players: giving weapons, stripping every weapon, or clearing tasks until a player falls out of their car. FXServer can block these game events server-wide with block_net_game_event:
block_net_game_event "GIVE_WEAPON_EVENT"
block_net_game_event "REMOVE_WEAPON_EVENT"
block_net_game_event "REMOVE_ALL_WEAPONS_EVENT"
block_net_game_event "NETWORK_CLEAR_PED_TASKS_EVENT"
Weapon systems that work through a server-side inventory are not affected, because they do not fire these events at other players. Some police scripts that clear another player's tasks from the client (cuffing, dragging) may need fixing, so test on a dev server first. As with layer 1, restart the whole server.
Explosions: log first, then block
local allowedExplosion = {}
local enforce = false
AddEventHandler('explosionEvent', function(sender, ev)
if allowedExplosion[ev.explosionType] then return end
print(('[explosion] %s (%s) type=%d'):format(GetPlayerName(sender), sender, ev.explosionType))
if enforce then CancelEvent() end
end)
Run it with enforce = false for a week. Note the explosion types that come from normal play (vehicles blowing up, gas pumps, heist scripts that use explosives), add them to allowedExplosion, then switch to enforce = true. Block straight away without logging and you will break your own heists.
If you cannot enable entity lockdown yet
While you migrate scripts to server-side entity creation, use entityCreating to cancel models that should never exist in your city:
local blockedModels = {
[`rhino`] = true,
[`hydra`] = true,
[`lazer`] = true,
}
AddEventHandler('entityCreating', function(entity)
if blockedModels[GetEntityModel(entity)] then
CancelEvent()
end
end)
Heavy weapons (RPG, Minigun, Railgun) should not exist in your item system at all. If someone uses one, they got it the wrong way. Log it and alert an admin.
Layer 4: identity and ban evasion
A ban means nothing if the cheater is back on a new account in five minutes. The first gate is the connection:
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
local src = source
deferrals.defer()
Wait(0)
local license = GetPlayerIdentifierByType(src, 'license')
local discord = GetPlayerIdentifierByType(src, 'discord')
if not license or not discord then
return deferrals.done('Open Discord and sign in to Rockstar before joining.')
end
if isBanned(license) or isBanned(discord) then
return deferrals.done('This account is banned. Contact staff on Discord.')
end
for i = 0, GetNumPlayerTokens(src) - 1 do
if isBanned(GetPlayerToken(src, i)) then
return deferrals.done('This PC is banned. Contact staff on Discord.')
end
end
deferrals.done()
end)
isBanned is your own ban-database lookup. What this does:
- Requires Discord + Rockstar license. Players without both cannot join, so a banned cheater has to replace several accounts at once.
- Bans by machine token.
GetPlayerTokenreturns hardware-bound values, which give you a basic machine-level ban. When you ban, store every identifier and every token. - Account Lock. Bind the license + discord (+ steam if you use it) set to the character the first time it is seen. If the same license comes back with a different Discord account, refuse and ask the player to contact an admin.
A Discord whitelist (players must be in your Discord to join) works by calling the Discord API through a bot during playerConnecting. Store the bot token in server.cfg with set only. Never use setr (replicated to every client) or sets (published in the server's public info).
Watch out for internet cafés. Many people share one PC, so tokens repeat. When an account's token matches a banned player, send it to an admin. Do not auto-ban on a token alone. The same goes for duplicate accounts (several licenses on one machine): treat it as supporting evidence, not a verdict.
Don't want to build this yourself? X3D Admin Panel (free) bans on identifiers + machine tokens, keeps a database of everyone who ever joined with the accounts that share a machine, and imports bans from txAdmin. By default it adds new accounts from the same machine to the existing ban (spreadOnEvade in config/config.sanctions.lua); if many of your players come from internet cafés, weigh that setting against the point above.
Layer 5: logs and evidence
No anticheat does not mean no visibility. Free tools to use fully:
- txAdmin: bans, warnings, player history and an admin action log built in. Always ban through txAdmin so there is a record of who banned whom and why (full setup in the txAdmin guide).
- X3D Admin Panel (free) stores money, item, job, chat, join/leave and every admin action in the database, searchable per player in one panel, and admins cannot act on an equal or higher rank.
- Log every money and item change to the database, and send only anomalies to Discord. Discord webhooks are rate-limited; at 2,000 players you cannot send every entry, and nobody could read them anyway.
- screenshot-basic, the Cfx.re resource, lets admins capture a suspect's screen and keep it as evidence before deciding.
- Your admin team can spectate through txAdmin. A 2,000-player city needs people watching logs in shifts, not only when someone reports.
What not to publish
You can say your server "has protection". Do not publish detection details, thresholds, or the names of your protection resources on your website or public Discord; that is an evasion manual for cheat makers. And never write "100% cheat-proof". The day someone meets a cheater and reads that line, your server loses its credibility.
What changes at 2,000 players
- FXServer has built-in net event rate limiters (
rateLimiter_netEvent_*,rateLimiter_netEventFlood_*). The defaults suit most servers. If normal players get dropped for event floods, find the script that fires events too often and fix it, instead of raising the limit for cheaters too. - Entity lockdown matters more. Twenty modified clients spawning entities at once is enough to make the whole city stutter.
- Logs belong in a database, not in files or one webhook per entry, and they must be searchable by identifier.
- The Discord check at join needs a cache. After a restart, a thousand-plus players connect at once; one Discord API call per player hits rate limits and the queue stalls.
- Your admin team is part of the protection. No tool replaces people who read the logs and decide on evidence.
When you do need an anticheat
With all five layers in place, what is left is purely client-side cheating: god mode, speed hacks, noclip, invisibility, aimbot. Those need detection running on the player's PC, which is an anticheat's job. Free and paid options are compared in FiveM anticheat, free vs paid.
X3D Anti-Cheat is built to sit on top of this foundation: screenshot evidence sent to Discord, in-city admin alerts, HWID bans, Steam + Discord account lock, and humans deciding the unclear cases. Try it free for 7 days on your live server. To see what happened around a flagged moment, X3D Replay (BETA, ESX) lets admins watch any player back in game with their pressed keys.
FAQ
Vehicles from the garage or props in hand disappeared after sv_entityLockdown relaxed. Now what? — That script creates entities on the client. Fix it to create them on the server, or switch to a lockdown-compatible script. Meanwhile, apply lockdown only to some routing buckets, or use entityCreating to block forbidden models.
Will block_net_game_event break police weapon confiscation? — Not if confiscation goes through a server-side inventory. Scripts that strip another player's weapons straight from the client will stop working, but that is the same route cheat menus use, so those scripts need fixing anyway.
Many people share PCs at internet cafés. Will a token ban hit them? — It can. Use tokens as supporting evidence and send matches to an admin, not as an automatic ban.
Once all five layers are in, am I 100% protected? — No server is. These five layers close the most damaging routes (money exploits, spawning, griefing, ban evasion). The rest is an anticheat and your admin team.
No budget for scripts at all. Where do I start? — Use a core that locks the economy before restarts and scripts that validate on the server; free ones are in free FiveM scripts. Plan the rest with the FiveM server budget guide.