Skip to content

Crafting location checks (job/gang/citizenid) are never enforced server-side #48

Description

@Pajt9whauht283as

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.craftItemverifyRecipe), 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions