Skip to content

Security finding - PlayerState.tunnel:update merges arbitrary keys into persisted character state (weapons/health survive death) #704

Description

@Pajt9whauht283as

Security report (responsible disclosure)

PlayerState.tunnel:update() merges arbitrary client tables into persisted character state

Affected: vrp/modules/player_state.lua:243-252; persistence at User.lua:46; replay logic player_state.lua:198-215

function PlayerState.tunnel:update(state)
  local user = vRP.users_by_source[source]
  if user and user:isReady() then
    for k,v in pairs(state) do
      user.cdata.state[k] = v      -- ← no key whitelist
    end
    vRP:triggerEvent("playerStateUpdate", user, state)
  end
end

No whitelist on keys. cdata.state is serialized to the database on save and replayed on every spawn: weapons are granted from stored state (:207), health/armour restored (:209-215), position teleports applied (:198-200).

Exploit chain

Client sends:

update({ weapons = { WEAPON_RAILGUN = { ammo = 250 } }, health = 200, custom_key = anything })

→ state persists across deaths and relogs; the "clear weapons/health on death" logic (:222-228) is bypassed because the client re-pushes state after each wipe. Beyond the direct weapon/health persistence abuse, this is uncontrolled key injection into a persisted blob that other modules read (in_owned_vehicle, customization), making future consumers attacker-configurable.

Suggested fix

Whitelist exactly the fields clients are meant to report (weapons, health, armour, position, heading, customization), type/range-check values, and treat weapons as non-persistable across death.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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