InstanceSandboxer
A class for wrapping and unwrapping Instances and RBXScriptSignals.
Types
AnyFn
type AnyFn = (...any) → ...anyFunction type that all functions can be reduced to.
MetamethodHook
Type for metamethod hook functions.
First argument is the original metamethod function that can be called.
This function expects an unwrapped Instance as its first argument.
Second argument is the wrapped Instance.
Remaining arguments are the arguments passed to the metamethod at invocation.
Properties
Instances
This item is read only and cannot be modified. Read Only
A set of all Instances that have been accessed in the sandbox,
including those that were created by the sandbox and those that were not.
This is used for tracking all Instances that may have been modified by
sandboxed code, so that they can be cleaned up or handled differently if necessary.
When Config.TrackInstances is enabled, any Instance that is accessed
in the sandbox will be added here. Keep in mind newly-created Instances
will be added here as well, so this will also include all Instances in
InstanceSandboxer.NewInstances. New Instances that were created and
were found to be forbidden via InstanceList.ForbiddenClasses will not
be added to this set.
To iterate through these Instances and clear them, you can do something like this:
for inst in InstanceSandboxer.Instances do
-- Your cleanup code here, such as:
inst:Destroy()
end
-- Instances get GC'd once destroyed, so this
-- is sufficient for cleanup in most cases,
-- but you can also do:
table.clear(InstanceSandboxer.Instances)
NewInstances
This item is read only and cannot be modified. Read Only
A set of Instances that have been created in the sandbox.
This is used for tracking Instances that were created by
sandboxed code, so that they can be cleaned up or handled
differently if necessary.
When Config.TrackInstances is enabled, any Instance that is created
will be added here. Keep in mind these will also be added to
InstanceSandboxer.Instances, since they are also accessed in the sandbox.
To iterate through these Instances and clear them, you can do something like this:
for inst in InstanceSandboxer.NewInstances do
-- Your cleanup code here, such as:
inst:Destroy()
end
-- Instances get GC'd once destroyed, so this
-- is sufficient for cleanup in most cases,
-- but you can also do:
table.clear(InstanceSandboxer.NewInstances)
RBXScriptConnections
This item is read only and cannot be modified. Read Only
A set of RBXScriptConnections that have been created by the sandbox.
This is used for tracking connections so that they can be cleaned up
when necessary. This will only be populated if and only if
Config.TrackRBXScriptConnections is enabled.
To iterate through these connections and clear them, you can do something like this:
for conn in InstanceSandboxer.RBXScriptConnections do
conn:Disconnect()
end
-- RBXScriptConnections get GC'd once disconnected,
-- so this is sufficient for cleanup in most cases,
-- but you can also do:
table.clear(InstanceSandboxer.RBXScriptConnections)
Functions
deepWrap
InstanceSandboxer.deepWrap(v: any,--
The value to deeply wrap.
key: string?,--
The key of the property, method, or event being wrapped, if applicable.
freeze: boolean?,pvisited: {[any]: any}?) → any
Deeply wraps v if it is a table, wrapping Instances and RBXScriptSignals as needed.
If v is an Instance or RBXScriptSignal, it will be wrapped and returned.
deepUnwrap
InstanceSandboxer.deepUnwrap(v: any,--
The value to deeply unwrap.
freeze: boolean?,--
Whether to freeze tables.
pvisited: {[any]: any}?) → any
Deeply unwraps v if it is a table, unwrapping Instances and RBXScriptSignals as needed.
If v is a wrapped Instance or RBXScriptSignal, it will be unwrapped and returned.
unwrapArgs
InstanceSandboxer.unwrapArgs(...: any) → ...any
Deeply unwraps all arguments passed to the function (usually
from inside the sandbox), making them ready to be used in a
method call on an Instance.
wrapArgs
InstanceSandboxer.wrapArgs(...: any) → ...anyDeeply wraps all arguments passed to the function, making them ready to be returned to the sandboxed environment.
wrapFn
InstanceSandboxer.wrapFn(passthroughIn: boolean,--
Whether to passthrough arguments untouched.
passthroughOut: boolean--
Whether to passthrough return values untouched.
) → AnyFn--
The wrapped function.
Wraps a function in a proxy that allows it to be safely used in the sandbox. The wrapped function will return wrapped arguments when called.
reverseWrapFn
Wraps a function in a proxy that allows it to be safely used outside the sandbox. This is mainly used for callbacks being added for things like BindableFunctions.
wrapEvent
InstanceSandboxer.wrapEvent(name: string--
The name of the signal, used for debugging purposes and printing out to console.
) → any--
The wrapped RBXScriptSignal.
Wraps an RBXScriptSignal in a proxy that allows it to be safely used in
the sandbox. The proxy will have the same methods as an RBXScriptSignal,
but will return wrapped arguments when the signal is fired.
wrapInstance
InstanceSandboxer.wrapInstance(fromInstanceConstructor: boolean?) → any--
The wrapped Instance.
Wraps an Instance in a proxy that allows it to be safely used in the sandbox.
The proxy will have the same properties, methods, and events as the Instance,
but will return wrapped arguments when accessed.
hookMetamethod
InstanceSandboxer.hookMetamethod(name: Metamethod,--
Metamethod name (with or without __ prefix) to hook.
) → ()
Hooks a specific metamethod on a wrapped Instance. Allows for hooking functions
on Instances, modifying behaviors, or changing properties within sandboxed code.
Safety Guarantees
selfreceived by the hook is always the wrapped proxy; it is never auto-unwrapped.- Every additional argument reaches the hook untouched; no wrapping, unwrapping, or copying occurs.
- Return values flow straight back to the sandbox exactly as yielded by the hook; no automatic wrapping occurs.
-
The hook therefore must explicitly call
InstanceSandboxer.unwrap,deepUnwrap,wrapInstance,deepWrap, orwrapArgswhenever data crosses the sandbox boundary. It is the caller's responsibility to ensure that this occurs correctly.
Behavior
- The hook completely replaces the default handling of the selected metamethod for
inst.-
The option to revert to conditionally default behavior is available by calling the first argument,
which is the original metamethod function. This function expects an unwrapped
Instanceas its first argument, followed by any additional arguments passed to the metamethod. It is highly recommended to passthrough arguments untouched to avoid unexpected behavior.
-
The option to revert to conditionally default behavior is available by calling the first argument,
which is the original metamethod function. This function expects an unwrapped
- If the hook does not call the original metamethod function, the default behavior is skipped.
- Hooks do not chain; setting a hook for a metamethod that already has one overwrites the previous hook.
- Hooks are per-instance, not inherited.
unwrap
InstanceSandboxer.unwrap(a: any--
The wrapped Instance or RBXScriptSignal to unwrap.
) → (Instance | RBXScriptSignal)?
Unwraps a wrapped Instance or RBXScriptSignal.
If the Instance or RBXScriptSignal is not wrapped, it will return nil.
isWrapped
InstanceSandboxer.isWrapped(a: any) → booleanChecks if a is a wrapped Instance.
isWrappedSignal
InstanceSandboxer.isWrappedSignal(a: any) → booleanChecks if a is a wrapped RBXScriptSignal.