Overview
Sandboxing restricts what Lua scripts can access, preventing malicious or untrusted code from harming your application or system.
Security Presets
SolarSharp provides three security presets via CoreModules:
Preset_HardSandbox (Most Restrictive)
Script script = new Script ( CoreModules . Preset_HardSandbox );
Includes only:
string - String manipulation
math - Mathematical functions
table - Table operations
bit32 - Bitwise operations
Basic functions (assert, type, tonumber, tostring)
Table iterators (pairs, ipairs, next)
Global constants (_G, _VERSION)
Excludes:
❌ File I/O (io, file)
❌ OS functions (os.execute, os.exit)
❌ Code loading (load, require, dofile)
❌ Debugging (debug)
❌ Coroutines
Use case: Running completely untrusted code (user scripts, plugins)
Preset_SoftSandbox (Balanced)
Script script = new Script ( CoreModules . Preset_SoftSandbox );
Adds to HardSandbox:
✅ Metatables (setmetatable, getmetatable)
✅ Error handling (pcall, xpcall)
✅ Coroutines (coroutine.*)
✅ Time functions (os.time, os.date, os.clock)
✅ JSON parsing (json)
✅ Dynamic code (load, loadfile)
Still excludes:
❌ File I/O
❌ System commands (os.execute)
❌ Debugging
Use case: Trusted user scripts that need more features
Preset_Default (Full Access)
Script script = new Script ( CoreModules . Preset_Default );
// or
Script script = new Script (); // Default
Includes everything except:
⚠️ Debugging (still excluded)
Use case: Internal scripts, development, trusted code
Preset_Complete (No Restrictions)
Script script = new Script ( CoreModules . Preset_Complete );
Includes everything:
✅ All standard library modules
✅ Debugging functions
Grants full system access . Only use for completely trusted scripts!
Custom Module Selection
Combine individual modules using flags:
Script script = new Script (
CoreModules . Basic |
CoreModules . String |
CoreModules . Math |
CoreModules . Table |
CoreModules . ErrorHandling
);
Available Modules
Module Description Basicassert, collectgarbage, error, print, select, type, tonumber, tostringGlobalConsts_G, _VERSION, _SOLARSHARPTableIteratorsnext, ipairs, pairsMetatablessetmetatable, getmetatable, rawset, rawget, rawequal, rawlenStringstring packageLoadMethodsload, loadsafe, loadfile, loadfilesafe, dofile, requireTabletable packageErrorHandlingpcall, xpcallMathmath packageCoroutinecoroutine packageBit32bit32 packageOS_Timeos.clock, os.difftime, os.date, os.timeOS_Systemos.execute, os.exit, os.getenv, os.remove, os.rename, os.tmpnameIOio and file packagesDebugdebug package (limited support)Jsonjson package (SolarSharp extension)
Restricting CLR Access
Limit what C# types scripts can access:
Don’t Register Types
The simplest approach:
// Don't do this for sandboxed scripts:
// UserData.RegisterType<DangerousClass>();
Script script = new Script ( CoreModules . Preset_HardSandbox );
// Scripts can't access DangerousClass
Remove Dangerous Globals
Script script = new Script ();
// Remove potentially dangerous functions
script . Globals [ "require" ] = LuaValue . Nil ;
script . Globals [ "dofile" ] = LuaValue . Nil ;
script . Globals [ "loadfile" ] = LuaValue . Nil ;
Provide Safe Wrappers
Script script = new Script ( CoreModules . Preset_HardSandbox );
// Safe print that logs instead of Console.WriteLine
script . Globals [ "print" ] = ( Action < string >)( msg =>
{
Logger . Info ( $"Script output: { msg } " );
});
// Safe file read with whitelist
script . Globals [ "read_file" ] = ( Func < string , string >)( filename =>
{
string [] whitelist = { "config.txt" , "data.json" };
if ( ! whitelist . Contains ( filename ))
throw new SecurityException ( "File not allowed" );
return File . ReadAllText ( filename );
});
Environment Isolation
Give each script its own isolated environment:
Script script = new Script ( CoreModules . Preset_SoftSandbox );
Table env1 = new Table ( script );
Table env2 = new Table ( script );
// Register modules in each environment
env1 . RegisterCoreModules ( CoreModules . Preset_HardSandbox );
env2 . RegisterCoreModules ( CoreModules . Preset_HardSandbox );
// Run scripts in separate environments
script . DoString ( "x = 10" , env1 );
script . DoString ( "print(x)" , env1 ); -- prints 10
script . DoString ( "print(x)" , env2 ); -- prints nil (isolated)
Stream Redirection
Redirect stdin/stdout/stderr to control I/O:
Script script = new Script ();
// Redirect stdout to memory
MemoryStream stdout = new MemoryStream ();
script . Options . Stdout = stdout ;
// Redirect stderr
MemoryStream stderr = new MemoryStream ();
script . Options . Stderr = stderr ;
// Provide custom stdin
string input = "user input \n " ;
MemoryStream stdin = new MemoryStream ( Encoding . UTF8 . GetBytes ( input ));
script . Options . Stdin = stdin ;
script . DoString ( "print('hello')" );
// Read captured output
stdout . Seek ( 0 , SeekOrigin . Begin );
string output = new StreamReader ( stdout ). ReadToEnd ();
Console . WriteLine ( $"Captured: { output } " );
Timeout Execution
Prevent infinite loops with timeouts:
using System . Threading ;
Script script = new Script ( CoreModules . Preset_HardSandbox );
CancellationTokenSource cts = new CancellationTokenSource ();
cts . CancelAfter ( TimeSpan . FromSeconds ( 5 )); // 5 second timeout
Task task = Task . Run (() =>
{
try
{
script . DoString ( @"
while true do
-- Infinite loop
end
" );
}
catch ( Exception ex )
{
Console . WriteLine ( $"Script error: { ex . Message } " );
}
}, cts . Token );
try
{
task . Wait ();
}
catch ( AggregateException ex ) when ( ex . InnerException is TaskCanceledException )
{
Console . WriteLine ( "Script execution timed out" );
}
SolarSharp doesn’t have built-in instruction counting. Use OS-level timeouts or manual instrumentation.
Sandboxing Best Practices
Start restrictive : Use Preset_HardSandbox by default
Whitelist, don’t blacklist : Only expose necessary functions
Validate inputs : Sanitize all data from scripts
Limit resources : Set timeouts and memory limits
Log activity : Monitor what scripts are doing
Regular audits : Review exposed functions periodically
Update dependencies : Keep SolarSharp up to date
Example: Secure Plugin System
public class PluginManager
{
private readonly Script _script ;
public PluginManager ()
{
// Create sandboxed environment
_script = new Script ( CoreModules . Preset_HardSandbox );
// Provide safe API
_script . Globals [ "api" ] = new PluginAPI ();
// Redirect I/O
_script . Options . Stdout = new MemoryStream ();
_script . Options . Stderr = new MemoryStream ();
}
public void LoadPlugin ( string code )
{
// Timeout after 10 seconds
CancellationTokenSource cts = new CancellationTokenSource ();
cts . CancelAfter ( TimeSpan . FromSeconds ( 10 ));
Task . Run (() => _script . DoString ( code ), cts . Token ). Wait ();
}
}
public class PluginAPI
{
public void Log ( string message )
{
// Safe logging
Console . WriteLine ( $"[Plugin] { message } " );
}
public string GetData ( string key )
{
// Whitelist allowed keys
if ( key != "allowed_key" )
throw new SecurityException ( "Key not allowed" );
return "safe data" ;
}
}
See Also
ScriptOptions Configure script behavior
Custom Modules Create safe custom modules