Description
ps_lib:craftItem in modules/psui/server/Crafting.lua (lines 66-83) never enforces the checks field configured on crafting locations:
RegisterNetEvent('ps_lib:craftItem', function(data, info)
local src = source
local itemVerify = CraftingTable[info.script][info.zone].recipes[data.item]
if not itemVerify then
ps.notify(src, 'Invalid item', 'error')
return
end
if not ps.checkDistance(src, CraftingTable[info.script][info.zone].loc[info.location].loc, 2.5) then
ps.notify(src, 'You are too far away', 'error')
return
end
ps.craftItem(src, {
take = itemVerify.recipe or {},
give = {
[data.item] = itemVerify.amount or 1
},
})
end)
The crafting table schema explicitly supports access restriction (lines 8-13):
--checks = { -- can either be strings OR tables
-- job = {'police', 'ambulance'},
-- items = {'lockpick'},
-- gang = {'ballas', 'vagos'},
-- citizenid = {'1234567890'}
--},
But the server handler only checks that the item exists and that the player is within 2.5 units of one of the configured locations. None of the checks are ever evaluated — a quick search for checks across the crafting module shows they are only read in the config documentation, never in the server handler (or the client UI for that matter).
Impact
Any player can craft items from restricted recipes by simply triggering ps_lib:craftItem while standing at the crafting location:
- Police-only recipes (armor, weapons) become craftable by civilians
- Gang-restricted crafting becomes available to everyone
citizenid-restricted recipes (personal/whitelisted crafting) are bypassable
items-restricted recipes (e.g. requires a key item to even attempt the craft) are bypassable — note the client UI may hide these, but the server event itself has zero gate
The recipes and ingredient costs are enforced server-side (via ps.craftItem → verifyRecipe), so the exploit is specifically about access control, not free items.
Suggested fix
In ps_lib:craftItem, evaluate itemVerify.checks (or the location-level checks) server-side before calling ps.craftItem:
local location = CraftingTable[info.script][info.zone]
local checks = itemVerify.checks or location.checks
if checks then
if not ps.checkChecks(src, checks) then
ps.notify(src, 'You are not allowed to craft this', 'error')
return
end
end
Affected file
modules/psui/server/Crafting.lua - ps_lib:craftItem
Description
ps_lib:craftIteminmodules/psui/server/Crafting.lua(lines 66-83) never enforces thechecksfield configured on crafting locations:The crafting table schema explicitly supports access restriction (lines 8-13):
But the server handler only checks that the item exists and that the player is within 2.5 units of one of the configured locations. None of the
checksare ever evaluated — a quick search forchecksacross the crafting module shows they are only read in the config documentation, never in the server handler (or the client UI for that matter).Impact
Any player can craft items from restricted recipes by simply triggering
ps_lib:craftItemwhile standing at the crafting location:citizenid-restricted recipes (personal/whitelisted crafting) are bypassableitems-restricted recipes (e.g. requires a key item to even attempt the craft) are bypassable — note the client UI may hide these, but the server event itself has zero gateThe recipes and ingredient costs are enforced server-side (via
ps.craftItem→verifyRecipe), so the exploit is specifically about access control, not free items.Suggested fix
In
ps_lib:craftItem, evaluateitemVerify.checks(or the location-levelchecks) server-side before callingps.craftItem:Affected file
modules/psui/server/Crafting.lua-ps_lib:craftItem