You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Security] Missing authorization checks: IDOR on player outfits, unauthorized management-uniform tampering, and money duplication via negative tattoo cost #524
Database.PlayerOutfits.Update (server/database/playeroutfits.lua:25) runs UPDATE player_outfits SET model = ?, components = ?, props = ? WHERE id = ? with no citizenid filter. Outfit IDs are auto-increment and enumerable, so any player can overwrite any other player's saved outfits (appearance data tampering).
Database.PlayerOutfits.DeleteByID (playeroutfits.lua:34) runs DELETE FROM player_outfits WHERE id = ? with no ownership check. Any player can delete any other player's outfits.
Direct INSERT INTO management_outfits with no job/grade check (compare getManagementOutfits at server.lua:136, which validates job + grade). Any player can inject management uniforms for any job/gang (e.g. police, MinRank=0), forcing arbitrary models on all job members.
local cost = tattoo.cost or Config.TattooCost takes the cost from the client-supplied payload (sent from NUI, game/nui.lua:84). A negative value passed to Framework.RemoveMoney(src, 'cash', cost) results in a credit instead of a debit on both supported frameworks (ESX RemoveAccountMoney and QBCore PlayerData.money.cash - amount both add money for negative amounts; the ESX balance check at server/framework/esx/main.lua:25 also passes).
Impact
Tampering/destruction of any player's saved outfits.
Corruption/deletion of job & gang management uniforms server-wide.
updateOutfit/deleteOutfit: verify ownership (e.g. local o = Database.PlayerOutfits.GetByID(id); if o and o.citizenid == citizenID then ...).
saveManagementOutfit/deleteManagementOutfit: validate job + grade server-side like getManagementOutfits does.
payForTattoo: never trust the client cost — clamp to Config.TattooCost or ignore tattoo.cost entirely.
I can provide full PoC payloads privately. There is no SECURITY.md / private vulnerability reporting enabled on this repo — happy to switch to a private channel if preferred.
Activity