Skip to content

OpenCompanyApp/lua-sandbox

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lua-sandbox

A sandboxed Luau runtime for PHP, built as a native extension in Rust.

Replaces the Wikimedia php-luasandbox PECL extension (~4,300 lines of C) with ~840 lines of Rust, using Luau instead of Lua 5.1.

Features

  • Luau runtime — Roblox's Lua fork with gradual type checking, better performance, and built-in sandboxing
  • CPU time limiting — per-script execution timeout via Luau's native interrupt mechanism (works on macOS and Linux)
  • Memory limiting — hard byte limit on Lua heap allocations
  • Sandbox hardening — no filesystem, network, or OS access; builtins are read-only
  • PHP callable bridge — register PHP functions callable from Lua, with automatic type conversion
  • Bidirectional conversion — PHP arrays/scalars to Lua tables and back, with circular reference detection
  • Exception hierarchyLua\TimeoutException, Lua\MemoryException, Lua\SyntaxException, Lua\RuntimeException

Requirements

  • PHP 8.4+
  • Linux x86_64 or macOS aarch64 (Apple Silicon)

Installation

Pre-built binaries (recommended)

Download from Releases:

Platform File
Linux x86_64 liblua_sandbox-linux-x86_64.so
macOS Apple Silicon liblua_sandbox-macos-aarch64.dylib

Copy to your PHP extension directory and enable:

# Find your extension dir
php-config --extension-dir

# Copy and enable
cp liblua_sandbox-linux-x86_64.so $(php-config --extension-dir)/liblua_sandbox.so
echo "extension=liblua_sandbox.so" > $(php --ini | grep "Scan" | cut -d: -f2 | xargs)/lua-sandbox.ini

Building from source

Requires: Rust 1.75+, PHP 8.4+ development headers, Clang/LLVM

cargo build --release
# Output: target/release/liblua_sandbox.{so,dylib}

Docker

ARG LUA_SANDBOX_VERSION=v1.0.0
RUN curl -fsSL "https://github.com/OpenCompanyApp/lua-sandbox/releases/download/${LUA_SANDBOX_VERSION}/liblua_sandbox-linux-x86_64.so" \
    -o "$(php-config --extension-dir)/liblua_sandbox.so" \
    && echo "extension=liblua_sandbox.so" > /usr/local/etc/php/conf.d/lua-sandbox.ini

PHP API

Lua\Sandbox

$sandbox = new \Lua\Sandbox(
    memory_limit: 10 * 1024 * 1024,  // 10 MB
    cpu_limit: 5.0,                   // 5 seconds
);

// Load and execute Luau code
$script = $sandbox->load('return 1 + 2');
$result = $script();        // [3] — via __invoke
$result = $script->call();  // [3] — explicit

// Register PHP functions callable from Lua
$sandbox->register('api', [
    'greet' => fn(string $name) => "Hello, {$name}!",
    'add'   => fn(int $a, int $b) => $a + $b,
]);
$sandbox->load('return api.greet("World")')();  // ["Hello, World!"]

// Wrap a single PHP callable as a Lua function
$double = $sandbox->wrap(fn($x) => $x * 2);
$double(21);  // [42]

// Call a global Lua function by name (supports dot notation)
$sandbox->load('function math.double(x) return x * 2 end')->call();
$sandbox->call('math.double', 21);  // [42]
Method Description
__construct(int $memory_limit = 0, float $cpu_limit = 0.0) Create sandbox. 0 = unlimited.
load(string $code, ?string $name): Script Compile Luau source
register(string $lib, array $fns): void Register PHP callbacks as a Lua library
wrap(callable $fn): Script Wrap single PHP callable
call(string $name, mixed ...$args): array Call global function (dot notation)
setMemoryLimit(int $bytes): void Change memory limit at runtime
memoryUsage(): int Current memory usage in bytes
peakMemoryUsage(): int Peak memory usage in bytes
setCpuLimit(float $seconds): void Change CPU limit at runtime
cpuUsage(): float CPU seconds consumed
pauseTimer(): bool / resumeTimer(): bool Pause/resume CPU timer
static version(): array Version info

Lua\Script

Method Description
call(mixed ...$args): array Execute, returns array of return values
__invoke(mixed ...$args): array Alias for call()

Exceptions

\Exception
  └─ Lua\Exception
      ├─ Lua\RuntimeException
      ├─ Lua\SyntaxException
      ├─ Lua\TimeoutException
      └─ Lua\MemoryException

Luau type annotations

Luau supports gradual typing. Type annotations are checked at analysis time:

local function fibonacci(n: number): number
    if n <= 1 then return n end
    return fibonacci(n - 1) + fibonacci(n - 2)
end

How it works

  • Sandbox: Luau's built-in sandbox(true) makes all builtins read-only and removes io, package, loadfile, dofile, string.dump, and debug (except traceback/info). Additional hardening filters the os table to only {clock, date, difftime, time}.
  • CPU timeout: Luau's native interrupt mechanism fires at every function call and loop iteration. No debug hooks or POSIX timers needed.
  • Memory: mlua's set_memory_limit() enforces a hard byte limit on the Lua allocator.
  • PHP bridge: Rust closures capture PHP callables and convert arguments bidirectionally. The CPU timer is paused during PHP execution.

License

MIT

About

Sandboxed Luau runtime for PHP — native Rust extension

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages