Skip to content

Scrubbers::Params skips Hash-like objects that are not Hash subclasses (ActionController::Parameters, etc.) #1204

Description

@AbdulrahmanAlamodi

Summary

Rollbar::Scrubbers::Params#scrub uses value.is_a?(Hash) to decide whether to recurse into nested structures. Objects that implement Ruby's implicit to_hash conversion but are not Hash subclasses — such as Rails'
ActionController::Parameters, are silently skipped. Their internal keys and values pass through completely unscrubbed, leaking credentials that scrub_fields would otherwise catch.

Environment

  • rollbar-gem: all versions through v3.8.0 (issue present on master)
  • Affected: ActionController::Parameters (Rails 5+), any object with to_hash that is not a Hash subclass

Reproduction

require "action_controller"

params = ActionController::Parameters.new(
  username: "user@example.com",
  password: "s3cret123"
).permit(:username, :password)

# scrub_fields defaults include :password
result = Rollbar::Scrubbers::Params.call(
  params: { body: params },
  config: Rollbar.configuration.scrub_fields
)

result[:body][:password]  # => "s3cret123" — NOT scrubbed

Real-world trigger: a Rails controller calls an external API via a service object. The request body (ActionController::Parameters from params.permit) is included in extra data passed to Rollbar.warning. When the API call fails, credentials
appear in plaintext in the Rollbar dashboard.

line 82

elsif value.is_a?(Hash)
scrub(value, options)

ActionController::Parameters (since Rails 5) does not inherit from Hash. is_a?(Hash) returns false, so the entire body is treated as an opaque scalar — all keys and values pass through unscrubbed.

The same gap exists in scrub_array at line 100:

line 100

value.is_a?(Hash) ? scrub(value, options) : rollbar_filtered_param_value(value)

Suggested Fix

Use Ruby's to_hash implicit conversion protocol to identify Hash-like objects:

+ def hash_like?(value)
+   value.is_a?(Hash) || value.respond_to?(:to_hash)
+ end

  def scrub(params, options)
    ...
-   elsif value.is_a?(Hash)
-     scrub(value, options)
+   elsif hash_like?(value)
+     scrub(value.is_a?(Hash) ? value : value.to_hash, options)
    ...
  end

  def scrub_array(array, options)
    array.map do |value|
-     value.is_a?(Hash) ? scrub(value, options) : rollbar_filtered_param_value(value)
+     hash_like?(value) ? scrub(value.is_a?(Hash) ? value : value.to_hash, options) : rollbar_filtered_param_value(value)
    end
  end

Why to_hash over to_h

to_hash is Ruby's implicit conversion protocol, only objects that genuinely signal "I am a Hash" implement it. to_h is broader: Array#to_h exists (Ruby 2.6+) and arrays must continue through scrub_array, not scrub.

Impact

Any Rails app that passes ActionController::Parameters through to an external API client will leak credentials, tokens, or other sensitive data into Rollbar when the API call fails. The scrub_fields configuration (which already includes
password, secret, token by default) silently has no effect on these objects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions