Ruby has implemented a multi-level security concept ever since. It is for controling security-relevant tasks and how a Ruby script executes them.
Dangerous operations from the Ruby perspective are accesses to environment variables, the file system or command line interpreters. That means entities defined outside of Ruby itself.
Everything that comes from these sources is insecure (or tainted):
File.read('README.md').tainted? # => true ENV['LANG'].tainted? # => true
Objects generated internally are not:
'Ruby'.tainted? # => false Fixnum.tainted? # => false
The tainted flag is defined on each and every object. Which operation is executeable for tainted objects depends on the SAFE level.
The tainted property is passed, like:
home = ENV['HOME'] home.tainted? # => true user = home.split('/')[-1] user.tainted? # => true
Ruby SAFE levels
Since version 2.3.0, Ruby scripts can be executed in two different SAFE levels (0 and 1). The levels 2 - 4 are no longer supported:
$SAFE = 3 # => $SAFE=2 to 4 are obsolete (ArgumentError)
The level 0 is set by default:
$SAFE # => 0
The SAFE Level can only be increased, but never be decreased:
$SAFE # => 0 $SAFE = 1 $SAFE # => 1 $SAFE = 0 # => SecurityError: tried to downgrade safe level from 1 to 0
Ruby - Tainted Love
It is briefly demonstrated, what happens, if a tainted object executes an operation, that is not allowed in its SAFE level.
# operation.txt puts 'Dangerous operation.'
The text file is read:
operation = File.read('operation.txt')
This string can be evaluated with SAFE level 0, but not with SAFE level 1:
$SAFE # => 0 eval(operation) # => "Dangerous operation." $SAFE = 1 eval(operation) # => SecurityError: Insecure operation - eval
Tainting an object is like:
ruby = 'Ruby' ruby.tainted? # => false ruby.taint ruby.tainted? # => true
And un-tainting it:
ruby.untaint ruby.tainted? # => false
However, it should also be clear whether the external source can be trusted or not.
Consequently classes also can be tainted, but this does not include tainting the class instances automatically:
String.tainted? # => false String.taint String.tainted? # => true String.new.tainted? # => false
Other Ruby implementations such as JRuby do not implement SAFE levels. JRuby is based on the JVM security model.