Project

ruby_box

0.0
No commit activity in last 3 years
No release in over 3 years
RubyBox allows the execution of untrusted Ruby code safely in a sandbox.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

~> 0.10
 Project Readme

RubyBox

Gem Version Build Status Code Climate Test Coverage Security

RubyBox allows the execution of untrusted Ruby code safely in a sandbox. It works by compiling Ruby code to JavaScript using opal and executing it in Google's V8 Engine with some help from mini_racer.

Installation

Add this line to your application's Gemfile:

gem 'ruby_box'

And then execute:

$ bundle

Or install it yourself as:

$ gem install ruby_box

Usage

# `RubyBox::Metal` is the sandbox base class. It has only the bare essentials to get the environment working.
class MySandbox < RubyBox::Metal
  # Code in the sandbox will block at most one second
  times_out_in 1.second

  # Makes the opal gem available for requiring inside the sandbox
  uses 'opal'

  # Requires the Opal compiler inside the sandbox (enables advanced runtime meta-programming like `Kernel#eval`)
  requires 'opal-parser'

  # Exposes the #native_add method to code running inside the sandbox
  exposes :native_add

  # Executes some code in the sandbox to setup it's runtime state
  executes <<-RUBY
    $global_state = 1337

    # Some boilerplate code
    class PlayThing
      attr_reader :name
    
      def initialize(name)
        @name = name
      end

      # Code inside of the sandbox can get a handle on the box with `RubyBox.current` and call exposed methods
      def add(a, b)
        RubyBox.current.native_add(a, b)
      end
    end
  RUBY

  def native_add(a, b)
    a + b
  end
end

untrusted_program = <<-RUBY
  $global_state = 'tainted'

  puts "Hello, world"
  
  car = PlayThing.new("Car")
  car.name
RUBY

# Every instance of the sandbox starts with the state configured on the class
my_sandbox = MySandbox.new
my_sandbox.execute(untrusted_program) #=> "Car"
my_sandbox.execute('PlayThing.add(2,7)') #=> 9
my_sandbox.stdout #=> ["Hello, world\n"]

# Every instance of the sandbox is isolated
another_sandbox = MySandbox.new
another_sandbox.execute('$global_state') #=> 1337

# It also has an stderr
another_sandbox.execute('warn "This looks dangerous"')
another_sandbox.stderr #=> ["This looks dangerous\n"]

# Exceptions comes through as subclasses of RubyBox::BoxedError
another_sandbox.execute('nil.no_method') #=> RubyBox::BoxedError::BoxedNoMethodError

# You can determine if you are in a sandbox using `RubyBox.boxed?` and `RubyBox.current`
RubyBox.boxed? #=> false
RubyBox.current #=> nil

Development

The development dependencies of this gem are managed using Bundler.

After checking out the repo, run bundle install to install dependencies. Then, run bundle exec rake spec to run the tests. You can also run bundle exec rake console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to RubyGems.

Contributing

Bug reports and pull requests are welcome on GitHub.

License

The gem is available as open source under the terms of the MIT License.