CVE-2017-1000248 (Ruby, published 2017-11-17T04:29Z)
Description: value: Redis-store <=v1.3.0 allows unsafe objects to be loaded from redis
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-502 \u2014 Deserialization of Untrusted Data
The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
Repository: https://github.com/redis-store/redis-store
Files changed:
lib/redis-store.rb
lib/redis/store.rb
lib/redis/store/factory.rb
lib/redis/store/namespace.rb
lib/redis/store/serialization.rb
test/redis/store/factory_test.rb
test/redis/store/namespace_test.rb
test/redis/store/serialization_test.rb
Commit message: Replace marshalling with pluggable serializers

This is in response to a vulnerability warning we received on Friday,
August 11th, 2017. While most users will not be affected by this
change, we recommend that developers of new applications use a different
serializer other than `Marshal`. This, along with the removal of the
`:marshalling` option, will enforce "sane defaults" in terms of securely
serializing/de-serializing data.

- Add `:serializer` option and deprecate `:marshalling`. Although you
  will still be able to enable/disable serialization with Marshal using
  `:marshalling` in the 1.x series, this will be removed by 2.0.

- Rename `Redis::Store::Marshalling` to `Redis::Store::Serialization` to
  reflect its new purpose.

Fixes #289


Vulnerable code:
require 'redis'
require 'redis/store/factory'
require 'redis/distributed_store'
require 'redis/store/namespace'
require 'redis/store/marshalling'
require 'redis/store/version'
require 'redis/store/redis_version'

class Redis
  class Store < self
  end
end
        @marshalling = !(options[:marshalling] === false) # HACK - TODO delegate to Factory
        extend Marshalling if @marshalling
        options[:raw] = !options[:marshalling]
          # Marshalling gets extended before Namespace does, so we need to pass options further
          if singleton_class.ancestors.include? Marshalling
    module Marshalling
          yield marshal?(options) ? Marshal.dump(val) : val
          unmarshal?(val, options) ? Marshal.load(val) : val
      it "allows/disable marshalling" do
        store = Redis::Store::Factory.create :marshalling => false
        store.instance_variable_get(:@marshalling).must_equal(false)
    @store  = Redis::Store.new :namespace => @namespace, :marshalling => false # TODO remove mashalling option
    let(:store){Redis::Store.new :namespace => @namespace, :marshalling => false}
describe "Redis::Marshalling" do
    @store = Redis::Store.new :marshalling => true

Fixed code:
require 'redis'
require 'redis/store/factory'
require 'redis/distributed_store'
require 'redis/store/namespace'
require 'redis/store/serialization'
require 'redis/store/version'
require 'redis/store/redis_version'

      unless options[:marshalling].nil?
        puts %(
          DEPRECATED: You are passing the :marshalling option, which has been
          replaced with `serializer: Marshal` to support pluggable serialization
          backends. To disable serialization (much like disabling marshalling),
          pass `serializer: nil` in your configuration.

          The :marshalling option will be removed for redis-store 2.0.
        )
      end

      @serializer = options.key?(:serializer) ? options[:serializer] : Marshal

      unless options[:marshalling].nil?
        @serializer = options[:marshalling] ? Marshal : nil
      end

        extend Serialization unless @serializer.nil?
        options[:raw] = case
                        when options.key?(:serializer)
                          options[:serializer].nil?
                        when options.key?(:marshalling)
                          !options[:marshalling]
                        else
                          false
                        end
          # Serialization gets extended before Namespace does, so we need to pass options further
          if singleton_class.ancestors.include? Serialization
    module Serialization
          yield marshal?(options) ? @serializer.dump(val) : val
          unmarshal?(val, options) ? @serializer.load(val) : val
require 'json'
      it "disables serialization" do
        store = Redis::Store::Factory.create :serializer => nil
        store.instance_variable_get(:@serializer).must_be_nil
      it "configures pluggable serialization backend" do
        store = Redis::Store::Factory.create :serializer => JSON
        store.instance_variable_get(:@serializer).must_equal(JSON)
        store.instance_variable_get(:@options)[:raw].must_equal(false)
      end

      describe 'with stdout disabled' do
        before do
          @original_stderr = $stderr
          @original_stdout = $stdout

          $stderr = Tempfile.new('stderr')
          $stdout = Tempfile.new('stdout')
        end

        it "disables marshalling and provides deprecation warning" do
          store = Redis::Store::Factory.create :marshalling => false
          store.instance_variable_get(:@serializer).must_be_nil
          store.instance_variable_get(:@options)[:raw].must_equal(true)
        end

        it "enables marshalling but provides warning to use :serializer instead" do
          store = Redis::Store::Factory.create :marshalling => true
          store.instance_variable_get(:@serializer).must_equal(Marshal)
          store.instance_variable_get(:@options)[:raw].must_equal(false)
        end

        after do
          $stderr = @original_stderr
          $stdout = @original_stdout
        end
      end

    @store  = Redis::Store.new :namespace => @namespace, :serializer => nil
    let(:store){Redis::Store.new :namespace => @namespace, :serializer => nil}
describe "Redis::Serialization" do
    @store = Redis::Store.new serializer: Marshal