# Somewhat hacked-together eval jail

**URL:** <https://www.ruby-forum.com/t/somewhat-hacked-together-eval-jail/180758>\
**Category:** Ruby\
**Created:** [December 28, 2009, 4:58pm UTC](https://www.ruby-forum.com/t/somewhat-hacked-together-eval-jail/180758 "2009-12-28T16:58:41Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![ngng](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/a88e4f/32.png) [@ngng](https://www.ruby-forum.com/u/ngng)\
**Post date:** [December 28, 2009, 4:58pm UTC](https://www.ruby-forum.com/t/somewhat-hacked-together-eval-jail/180758/1 "2009-12-28T16:58:41Z")

</div>

Hi everyone,

I’m working on a program where a lot of externally loaded scripts will  
be run. Although the scripts will all be written by trusted (or  
mostly trusted) sources, I want to implement some form of jail that is  
at least somewhat difficult to break out of to eval these scripts.

## So far, I’ve tried this:

```
jail = Module.new {
  def self.remove_const (...)
  def self.parent (...)
  def self.const_missing (...)
}
(Module.constants.collect{|c|c.to_sym} - ScriptJailWhitelist).each { 

```

## |const| jail.const\_set(const,nil) }

which adds local constants to my jail module that ‘override’ the  
global ones that would allow someone to break out (for example,  
TOPLEVEL\_BINDING) with the exception of a whitelist that I have  
defined (Array, Date, Hash, etc) In the initial declaration for the  
jail Module I also add methods for self.remove\_const, self.parent that  
simply raise an exception. Lastly I add a method for  
self.const\_missing because I have ActiveSupport loaded.

I then populate the jail module with methods needed for the script  
running and do jail.module\_eval in a new thread with safe\_level 3.  
(all this work because safe\_level 4 was too restrictive for what I  
needed… heh)

As far as possible security problems, perhaps there is a way to get  
the Object class (some\_instance.class) that would allow access to the  
TOPLEVEL\_BINDING constant once again… but I couldn’t find a way in  
my quick experiments.

I’m sure there are some holes in this design, but so far I can’t find  
any playing around in irb with a binding inside this Module. I’m  
hoping someone here might know the language a little better than me  
and point out anything obvious I might be missing. Again, this  
doesn’t need to be 100% secure, but hey if it is then that’s a bonus  
🙂

Or if there’s a better way to do this that I somehow missed, please  
enlighten me.

Thank you for your time,  
-Jonathan N.

---

<div class="post-metadata">

**Author:** ![ngng](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/a88e4f/32.png) [@ngng](https://www.ruby-forum.com/u/ngng)\
**Post date:** [December 28, 2009, 5:42pm UTC](https://www.ruby-forum.com/t/somewhat-hacked-together-eval-jail/180758/2 "2009-12-28T17:42:26Z")

</div>

On Mon, Dec 28, 2009 at 9:58 AM, Jonathan N. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Hi everyone,
> 
> I’m working on a program where a lot of externally loaded scripts will  
> be run. Although the scripts will all be written by trusted (or  
> mostly trusted) sources, I want to implement some form of jail that is  
> at least somewhat difficult to break out of to eval these scripts.

You may want to take a look at why\_sandbox if you are on 1.8 MRI ruby.

> ## So far, I’ve tried this:
> 
> jail = Module.new {  
> def self.remove\_const (…)  
> def self.parent (…)  
> def self.const\_missing (…)  
> }  
> (Module.constants.collect{|c|c.to\_sym} - ScriptJailWhitelist).each { |const|  
> jail.const\_set(const,nil)  
> }

Not a bad start.

When I tried to use a collection to contain malicious code in Try  
Ruby, I had my rear end handed to me.  
It was about as secure as allowing a printer read and write to your  
password file.

Also, it was slow. There are a lot of dirty ways to execute system  
commands.

$SAFE isn’t used all that often anymore, but it may help in your case.

> Thank you for your time,  
> -Jonathan N.

Andrew McElroy

---

<div class="post-metadata">

**Author:** ![ngng](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/a88e4f/32.png) [@ngng](https://www.ruby-forum.com/u/ngng)\
**Post date:** [December 28, 2009, 6:52pm UTC](https://www.ruby-forum.com/t/somewhat-hacked-together-eval-jail/180758/3 "2009-12-28T18:52:34Z")

</div>

On Mon, Dec 28, 2009 at 9:41 AM, andrew mcelroy [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> You may want to take a look at why\_sandbox if you are on 1.8 MRI ruby.

That’s actually what I found first, but I’d like my app to be ruby  
1.8.7 compatible… it looked like that required a patched version of  
1.8.6? I also looked into jruby which appeared to have a similar  
feature in the mainstream distribution, but I couldn’t get it to  
work…

> $SAFE isn’t used all that often anymore, but it may help in your case.

Yeah, setting $SAFE to 3 stopped every attempt at executing system  
commands that I tried. I wanted to set it to 4, but that proved to be  
too restrictive. Due to the nature of my program it was possible to  
create scripts that ran at a lower safe level if the safe level was  
set to 3 alone, so I hope that keeping people out of all classes  
except some whitelisted ones will solve that problem.

Thanks for the reply!

Is there a way in ruby of calling up a class without the constant that  
refers to it being accessible? If so, that would blow a big hole in  
my method here…

-Jonathan N.
