Rudel
Sandboxes

How Isolation Works

Each Rudel sandbox is fully isolated from the host WordPress installation and from other sandboxes. This page explains the mechanisms that make this possible.

SQLite database

Every sandbox gets its own SQLite database file (wordpress.db). This replaces the host's MySQL database entirely for that sandbox's context. Benefits:

  • No shared state: Sandboxes cannot read or write each other's data.
  • Instant creation: Creating a database is just copying a file.
  • Portable: The entire database is a single file that can be copied, exported, or deleted.
  • No credentials: Unlike MySQL, there are no connection strings or passwords to manage or leak.

The SQLite integration is handled by the WordPress SQLite Database Integration, which translates WordPress's MySQL queries to SQLite on the fly.

wp-content directory

Each sandbox has its own wp-content directory containing:

  • themes/: Sandbox-specific themes (copied from host)
  • plugins/: Sandbox-specific plugins
  • uploads/: Isolated media uploads
  • mu-plugins/: Sandbox must-use plugins

WordPress core files (wp-includes/, wp-admin/) are shared from the host installation. Only the content layer is isolated.

Table prefix

Each sandbox uses its own table prefix to avoid any collision, even though the databases are separate files. This provides defense-in-depth and ensures WP-CLI commands operate on the correct tables.

Bootstrap mechanism

The bootstrap.php file in each sandbox sets WordPress constants before WordPress boots:

  • DB_DIR and DB_FILE: Point to the sandbox's SQLite database.
  • WP_CONTENT_DIR and WP_CONTENT_URL: Point to the sandbox's wp-content.
  • WP_PLUGIN_DIR and WPMU_PLUGIN_DIR: Sandbox plugin directories.
  • WP_TEMP_DIR: Sandbox temp directory.
  • UPLOADS: Sandbox upload path.

These constants are set before wp-settings.php runs, so WordPress sees the sandbox as its entire world.

open_basedir restriction

The bootstrap sets PHP's open_basedir to restrict file access:

ini_set('open_basedir', implode(PATH_SEPARATOR, [
    $sandbox_path,          // Sandbox directory (read/write)
    $wp_core_path,          // Shared WP core (read)
    $rudel_plugin_dir,      // Rudel plugin directory (read)
    sys_get_temp_dir(),     // PHP temp directory
    '/tmp',                 // Fallback temp directory
]));

In CLI mode, the WP-CLI tool's own directory is also added to the allowlist.

Once set, any file operation outside these paths fails silently. The host's wp-config.php, other sandboxes, and the host database are all inaccessible from within a sandbox.

Authentication salts

Each sandbox gets its own set of authentication salts, deterministically derived from the sandbox ID at boot time. This means sessions and cookies from one sandbox are not valid in another, preventing cross-sandbox session hijacking.

WP-CLI scoping

Each sandbox includes a wp-cli.yml file:

path: /var/www/html
require:
  - /path/to/sandboxes/sandbox-{id}/bootstrap.php

Any wp command executed from within the sandbox directory automatically uses that sandbox's database and content. No flags needed.

Security model summary

Attack vectorDefense
Path traversal (../../)open_basedir blocks access outside allowlist
Sandbox escape to host DBSQLite is file-based, open_basedir restricts access
Cross-sandbox accessEach sandbox's open_basedir only includes its own path
Credential leakageNo MySQL credentials exist in sandbox context
Agent modifies its own jailbootstrap.php and wp-cli.yml are read-only
Prompt injection via DB/filesAgent instructions in read-only CLAUDE.md; sandbox is disposable

On this page