Skip to content

jeferls/bubblewrap-sandbox

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laravel Bubblewrap Guard

Security layer that forbids executing external commands without a bubblewrap sandbox. Designed for Laravel apps from 5 through 12 that need to process files (PDF, image, video, document) with mandatory bubblewrap (bwrap) isolation.

Why use this

  • Prevents RCE via unsafe shell_exec/exec/system/passthru/proc_open.
  • Isolates filesystem, environment variables, and network for the child process.
  • Compatible with PHP 5.6+ and Laravel 5.x to 12.x.

Installation

composer require greenn-labs/bubblewrap-sandbox

For Laravel >= 5.5, package auto-discovery already registers the provider and the BubblewrapSandbox alias.

For older versions, add manually in config/app.php:

Greenn\Libs\Laravel\BubblewrapServiceProvider::class,
'BubblewrapSandbox' => Greenn\Libs\Laravel\BubblewrapSandbox::class,

Publish the configuration (optional):

php artisan vendor:publish --tag=sandbox-config

Basic usage

use Greenn\Libs\BubblewrapSandbox;

$runner = app(BubblewrapSandbox::class); // or BubblewrapSandbox facade

// Command to run inside the sandbox
$command = array('gs', '-q', '-sDEVICE=png16m', '-o', '/tmp/out.png', '/tmp/in.pdf');

// Bind mounts for input/output (read-only by default)
$binds = array(
    array('from' => storage_path('uploads/in.pdf'), 'to' => '/tmp/in.pdf', 'read_only' => true),
    array('from' => storage_path('tmp'), 'to' => '/tmp', 'read_only' => false),
);

$process = $runner->run($command, $binds, '/tmp', null, 120);
$output = $process->getOutput();

Documentation

Security rules enforced

  • Every command is prefixed with bwrap and --unshare-all --die-with-parent --new-session.
  • Default mounts: /usr, /bin, /lib*, /sbin as read-only; /tmp isolated and writable.
  • PATH is limited (/usr/bin:/bin:/usr/sbin:/sbin).
  • If bwrap is unavailable or not executable, a BubblewrapUnavailableException is thrown.

Do not

  • Do not call shell_exec, exec, system, passthru, proc_open, or raw Symfony Process for sensitive binaries. Always go through BubblewrapSandbox.
  • Do not mount directories containing secrets (e.g., /home, /var/www/.env).

Configuration

Edit config/sandbox.php after publishing:

  • binary: path to bwrap.
  • base_args: default flags (avoid removing unshare/die-with-parent).
  • read_only_binds: automatic read-only binds.
  • write_binds: writable binds (default only /tmp).

Quick examples

  • Image with ImageMagick: ['convert', '/tmp/in.png', '-resize', '800x600', '/tmp/out.png'].
  • Video with FFmpeg: ['ffmpeg', '-i', '/tmp/in.mp4', '-vf', 'scale=1280:720', '/tmp/out.mp4'] plus binds for input/output paths.
  • PDF with Ghostscript: use the basic usage example.

Tests

  • Requires PHP ext-dom enabled.
  • Local run (single version):
    composer install --no-interaction --no-progress
    vendor/bin/phpunit
    On PHP 5.6–7.x, Composer will pull PHPUnit 5.7; on PHP 8.x it will use PHPUnit 9.6 (coverage is optional if xdebug/pcov are installed).
  • Matrix via Docker:
    chmod +x tools/test-matrix.sh
    tools/test-matrix.sh
    The script spins up PHP containers and runs PHPUnit across multiple PHP/Laravel pairs. Adjust the COMBOS list to narrow versions. Note: the current test suite uses anonymous classes, so the PHP 5.6/Laravel 5.4 combo is commented out (PHP 5.6 lacks that feature).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published