0.01
Repository is archived
No commit activity in last 3 years
No release in over 3 years
The psych_shield gem provides a configurable filter for the default Psych YAML parser in Ruby 1.9
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

Psych Shield

Psych Shield provides a way to filter objects during a YAML.load call when the Psych parser is used (default in Ruby 1.9). This can prevent malicious input to a YAML.load call from resulting in bad things within your application.

This is a dirty hack that allows applications that need to accept untrusted YAML input to continue doing so until they can be ported to a new format. Note that this DOES NOT protect against the full set of issues identified in CVE-2013-0156. The primary use case of this gem is to lock down YAML.load() calls.

To protect a Ruby on Rails application, add the following to Gemfile:

gem 'psych_shield'

Rails 2 applications should add an initializer that loads this gem.

$ echo 'require "psych_shield"' > config/initializers/load_psych_shield.rb

By default, Psych Shield allows the following types of objects:

Hash Array String Range
Numeric Fixnum Integer Bignum Float Rational Complex
Time DateTime
NilClass TrueClass FalseClass

To enable additional classes, add the stringified form using the "add" method:

PsychShield.add('MyClass::IsAwesome::And::Safe')

To disable all classes (even the defaults), use the clear method:

PsychShield.clear

To figure out what classes you need to allow, you can use the callback:

PsychShield.callback = Proc.new { |klass,result|
    $stderr.puts "#{ result ? "Allowed" : "Denied"} class #{klass}"
}

Denied objects are removed from the resulting ruby implementation

PsychShield passes all expected psych tests included in the Ruby source:

$ ruby -I lib/ -r psych_shield -I /usr/local/rvm/src/ruby-1.9.3-p194/test/ /usr/local/rvm/src/ruby-1.9.3-p194/test/psych/test_psych.rb
Run options: --seed 61780

# Running tests:

................F.....

Finished tests in 0.011105s, 1981.1699 tests/s, 3331.9675 assertions/s.

1) Failure:
test_non_existing_class_on_deserialize(TestPsych) [/usr/local/rvm/src/ruby-1.9.3-p194/test/psych/test_psych.rb:53]:
ArgumentError expected but nothing was raised.

22 tests, 37 assertions, 1 failures, 0 errors, 0 skips

The YAML test has one failure, as is expected (Struct::MyBookStruct was filtered):

$ ruby -I lib/ -r psych_shield -I /usr/local/rvm/src/ruby-1.9.3-p194/test/ /usr/local/rvm/src/ruby-1.9.3-p194/test/psych/test_yaml.rb
Run options: --seed 31567

# Running tests:

...........F.................................................

Finished tests in 0.200379s, 304.4230 tests/s, 1282.5688 assertions/s.

1) Failure:
test_ruby_struct(Psych_Unit_Tests) [/usr/local/rvm/src/ruby-1.9.3-p194/test/psych/test_yaml.rb:1039]:
--- expected
+++ actual
@@ -1 +1 @@
-[#<struct Struct::MyBookStruct author="Yukihiro Matsumoto", title="Ruby in a Nutshell", year=2002, isbn="0-596-00214-9">, #<struct Struct::MyBookStruct author=["Dave Thomas", "Andy Hunt"],     title="The     Pickaxe", year=2002, isbn=#<struct Struct::MyBookStruct author="This should be the ISBN", title="but I have another struct here", year=2002, isbn="None">>]
+[#<struct author="Yukihiro Matsumoto", title="Ruby in a Nutshell", year=2002, isbn="0-596-00214-9">, #<struct author=["Dave Thomas", "Andy Hunt"], title="The Pickaxe", year=2002, isbn=#<struct     author="This should be the ISBN", title="but I have another struct here", year=2002, isbn="None">>]


61 tests, 257 assertions, 1 failures, 0 errors, 0 skips