Repository navigation
fix: clientside RCE — network part data could retarget command parts to other players (PlayerOwner injection) - #1477
Merged
Techbot121 merged 1 commit intoOct 11, 2026
Conversation
SetTable applied every existing Set<key> setter from network-provided part tables, including internal ones (SetPlayerOwner, SetShowInEditor, SetOwner). Part data crosses the server to other clients, so any client could set internal state on parts worn by other players. ToTable() only serializes StorableVars, so restricting SetTable to StorableVars keys is fully backward compatible with existing outfits. Also strip internal keys from part.self serverside before rebroadcast, protecting clients that have not updated yet.
Collaborator
|
I'd also be inclined to apply punishment (a pac ban) or at least log it, since with your checks, these wrongful table keys are expected to only show up in a manually-injected data payload. As far as I know. |
pingu7867
pushed a commit
that referenced
this pull request
Oct 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Severity: Critical — clientside RCE
PART:SetTableapplied any existingSet<key>method from part tables received over the network, including internal ones. Because outfits are rebroadcast by the server to every client, a regular player could set the internal fieldPlayerOwneron parts worn by other players, retargeting the part's owner to the victim. Since command parts execute their owner's console commands/Lua whenGetPlayerOwner() == LocalPlayer, the attacker's code executes on the victim's client.Impact
sv_allowcsluaneeded): chat as the victim, screenshots, changing client convars, triggering any non-blocked console command.sv_allowcslua 1, common on build/sandbox servers):file.*writes into the victim'sDATAfolder, outbound HTTP from the victim (IP/SteamID exfiltration), installing clientside hooks (input control viaCreateMove, chat interception), freezing/crashing the client.ShowInEditor) and attach outfits to other players.Minimal PoC (conceptual)
The whole attack is one
pac_submitwhose part table contains an internal field:On the victim's client
PART:SetTable(base_part.lua) appliesSetPlayerOwner(victim)from the network table.WearPartFromServerthen callspart:CallRecursive("OnWorn")→command:OnWorn→Execute(), which checksGetPlayerOwner() == pac.LocalPlayer— now true for the victim — and runsent:ConCommand(self.String)on their client (parts/command.lua). WithUseLua = trueandsv_allowcslua 1, the same field placement leads toCompileString/execution of arbitrary Lua on the victim.A full weaponized PoC (including the wire serializer, persistence via outfit resync, editor invisibility, and a chat-controlled C2 payload) is available privately through GitHub security advisory on request.
Root cause
SetTable(base_part.lua) applies every existingSet<key>setter found in the network table — there is no restriction to declared (storable) properties, so internal setters such asSetPlayerOwnerandSetShowInEditorare reachable from client data that the server rebroadcasts.Fix
PART:SetTablenow only applies keys declared inStorableVars. This is backward compatible:PART:ToTable()only serializesStorableVars, so all existing saved/worn outfits are unaffected. Internal setters are no longer reachable from network data.PlayerOwner,PlayerOwnerHash,Owner,ShowInEditor) frompart.selfinpace.HandleReceivedDatabefore rebroadcasting, which also protects clients running older versions of the addon.Verification
StorableVarskeys are ever serialized).part.selfover the network are ignored clientside and removed serverside.