Ruby has implemented a multi-level security concept ever since. It is for controling security-relevant tasks and how a Ruby script executes them.
Security-relevant operations
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.