Product SiteDocumentation Site

2.4.3. JSON.parse and JSON.load

JSON format supports only several primitive data types such as strings, arrays, hashes, numbers etc. This certainly limits the attack surface, but it should not give developer false sense of security - one example is CVE-2013-0333 vulnerability in Ruby on Rails, when parser used for deserialization of JSON data actually converted data to a subset of YAML and used YAML.load to deserialize.
However, it is possible to extend Ruby classes to be JSON-dumpable:
class Range
def to_json(*a)
  {
    'json_class'   => self.class.name,
    'data'         => [ first, last, exclude_end? ]
  }.to_json(*a)
end

def self.json_create(o)
  new(*o['data'])
end
end
This will allow instances of Range class to be serialized with JSON:
>> (1..10).to_json
=> "{\"json_class\":\"Range\",\"data\":[1,10,false]}"
During deserialization, JSON gem will try to look up class referenced by "json_class", which might create new Symbol if the class does not exist, possibly allowing Denial of Service (see Section 2.3, “Symbols”):
>> Symbol.all_symbols.size
=> 3179
>> JSON.parse('{"json_class":"NonexistentClass"}')
ArgumentError: can't get const NonexistentClass: uninitialized constant NonexistentClass
>> Symbol.all_symbols.size
=> 3180
To disable this, :create_additions => false option can be passed as second argument:
>> JSON.parse('{"json_class":"NonexistentClass"}',:create_additions => false)
=> {"json_class"=>"NonexistentClass"}
This behaviour has changed in response to CVE-2013-0269 and JSON.parse now defaults to :create_additions => false. However, default behaviour has not changed for JSON.load, which is dangerous to call on untrusted input.