menu_bookDocumentation
RPC Security: How s&box Validates Incoming RPCs — Attribute Check, Permission Flags, Kick on Unauthorized
RPC Security: How s&box Validates Incoming RPCs
Understanding how s&box validates incoming RPCs is important for writing secure multiplayer code.
Validation Steps
When an RPC message arrives from the network, the engine performs these checks in order:
- GameObject lookup — The message contains the Guid of the target GameObject. If not found in the active scene, the RPC is dropped with a warning.
- Component lookup — If ComponentId != Guid.Empty, the target component is looked up. If not found, the RPC is dropped.
- Attribute check — The method must have an [RpcAttribute] (i.e., [Rpc.Broadcast], [Rpc.Host], or [Rpc.Owner]). If it doesn't, the calling connection is kicked: source.Kick( "Unauthorized RPC" ).
- Permission check — NetFlags.HostOnly and NetFlags.OwnerOnly are enforced:
Rpc.Owner Fallback Behavior
For [Rpc.Owner] RPCs, if the GameObject has no owner (OwnerId == Guid.Empty), the message is sent to the host instead. This means [Rpc.Owner] on an unowned object behaves like [Rpc.Host].
Local Execution
RPCs also execute locally on the caller. The engine checks:
- If Filter is active and the local connection is not a recipient, local execution is skipped.
- For [Rpc.Owner]: local execution only happens if IsOwner || (OwnerId == Guid.Empty && IsHost).
- For [Rpc.Host]: local execution only happens if Networking.IsHost.
Rpc.Caller Inside an RPC
CSHARP
[Rpc.Host]
public void RequestSomething()
{
// Rpc.Caller is the Connection that sent this RPC
// Rpc.Calling is true when called from the network
// Rpc.CallerId is the Guid of the caller
Log.Info( $"Called by: {Rpc.Caller.DisplayName}" );
}GameObjectSystem RPCs
RPCs can also be declared on GameObjectSystem subclasses. They are routed by the system's Guid rather than a GameObject Guid. For [Rpc.Owner] on a system, "owner" means the host.
Was this helpful?