Rubysec

Providing security resources for the Ruby community.
Follow us @rubysec or email us via info at rubysec.com

Advisory Archive

Back

---
gem: activerecord
date: 2016-08-11
url: https://groups.google.com/forum/#!topic/rubyonrails-security/rgO20zYW33s
cve: 2016-6317
title: Unsafe Query Generation Risk in Active Record
description: |
  There is a vulnerability when Active Record is used in conjunction with JSON
  parameter parsing. This vulnerability is similar to CVE-2012-2660,
  CVE-2012-2694 and CVE-2013-0155.

  Impact
  ------

  Due to the way Active Record interprets parameters in combination with the way
  that JSON parameters are parsed, it is possible for an attacker to issue
  unexpected database queries with "IS NULL" or empty where clauses.  This issue
  does *not* let an attacker insert arbitrary values into an SQL query, however
  they can cause the query to check for NULL or eliminate a WHERE clause when
  most users wouldn't expect it.

  For example, a system has password reset with token functionality:

  ```ruby
      unless params[:token].nil?
        user = User.find_by_token(params[:token])
        user.reset_password!
      end
  ```

  An attacker can craft a request such that `params[:token]` will return
  `[nil]`.  The `[nil]` value will bypass the test for nil, but will still add
  an "IN ('xyz', NULL)" clause to the SQL query.

  Similarly, an attacker can craft a request such that `params[:token]` will
  return an empty hash.  An empty hash will eliminate the WHERE clause of the
  query, but can bypass the `nil?` check.

  Note that this impacts not only dynamic finders (`find_by_*`) but also
  relations (`User.where(:name => params[:name])`).

  All users running an affected release should either upgrade or use one of the
  work arounds immediately. All users running an affected release should upgrade
  immediately. Please note, this vulnerability is a variant of CVE-2012-2660,
  CVE-2012-2694, and CVE-2013-0155.  Even if you upgraded to address those
  issues, you must take action again.

  If this chance in behavior impacts your application, you can manually decode
  the original values from the request like so:

      `ActiveSupport::JSON.decode(request.body)`

  Workarounds
  -----------
  This problem can be mitigated by casting the parameter to a string before
  passing it to Active Record.  For example:

    ```ruby
      unless params[:token].nil? || params[:token].to_s.empty?
        user = User.find_by_token(params[:token].to_s)
        user.reset_password!
      end
    ```
unaffected_versions:
- "< 4.2.0"
- ">= 5.0.0"
patched_versions:
- "~> 4.2.7.1"