Unsafe net events: the most common FiveM vulnerability is not a backdoor
The most common FiveM exploit: a server event that trusts the client. What an unsafe RegisterNetEvent handler looks like and the server-side fix.
Published Updated 3 min readFXScan team, Titan Software
Deliberate backdoors get the attention. The vulnerability that actually drains servers is duller: a server-side event handler that believes what the client told it.
The shape of it
RegisterNetEvent("shop:buyItem")
AddEventHandler("shop:buyItem", function(item, price)
local src = source
local player = GetPlayer(src)
player.removeMoney(price)
player.addInventoryItem(item, 1)
end)
price arrives from the client. Any player can call this event with any
arguments, including a negative price, an item that costs nothing, or an item
they were never meant to have. Nothing in that handler is a backdoor. The
author simply forgot that a network event is user input.
The exploited version is one line:
TriggerServerEvent("shop:buyItem", "weapon_rpg", -1000000)
Why it survives review
It survives because it reads like ordinary code. There is no obfuscation, no suspicious string, nothing that a grep would catch. The bug is the absence of something - a server-side lookup of the real price - and absences are hard to notice.
It also survives because it works. The shop functions correctly for every player who is not attacking it, so it passes testing.
The fix
Never accept a value the server can determine itself:
RegisterNetEvent("shop:buyItem")
AddEventHandler("shop:buyItem", function(item)
local src = source
local definition = SHOP_ITEMS[item] -- server-owned price list
if not definition then return end -- unknown item: refuse
local player = GetPlayer(src)
if player.getMoney() < definition.price then return end
player.removeMoney(definition.price)
player.addInventoryItem(item, 1)
end)
The client now sends only which item. Price, existence and affordability are all decided server-side.
The general rule
Treat every parameter of a server-side event handler as though it were typed by someone who wants your economy. The safe pattern is:
- the client says what it wants to do,
- the server decides whether that is allowed and what it costs.
Any handler that grants money, items, weapons, jobs or group membership using a number the client supplied is a finding. FXScan raises these as a category of their own - eleven rules covering money, item, weapon, job and permission grants reached from a client payload - because in practice they cost more servers more money than the backdoors do.
Beyond money and items
Economy grants are the most common case, not the only one. The same mistake
shows up as a handler that trusts a client-supplied player id instead of
source, a privileged event with no ACE check, a handler that writes client
values straight into the database, or one that rebroadcasts client data to
every player. The worst version executes the event's arguments outright - that
is no longer an economy bug but remote code execution.
Further reading
- FiveM RCE - when a net event reaches
load()orExecuteCommand. - Anatomy of a FiveM backdoor - the deliberate counterpart to this accidental bug.
- The unsafe network event rules in the detection catalogue.
Upload a resource to the FiveM backdoor scanner to find handlers like these automatically. Titan Software's FiveM server security guide covers the server-side controls - ACE permissions, anticheat - that sit around them.