Summary
Rollbar::RequestDataExtractor picks up the app's Rails parameter filters from env['action_dispatch.parameter_filter'] and merges them into scrubbing. Since Rails 7.1, config.precompile_filter_parameters (enabled by load_defaults "7.1" and later) makes Rails precompile that env value into a single combined Regexp instead of an array of names. Rollbar::Scrubbers::Params#build_fields_regex runs every entry through Regexp.escape(val.to_s), which turns the compiled regexp into a literal string that matches nothing.
Nothing raises — params, session, and cookie scrubbing silently degrades to the gem's small built-in scrub_fields default list. Any Rails app on load_defaults "7.1"+ that relies on filter_parameters being honored by Rollbar is sending those values unscrubbed in occurrence payloads.
Environment
- rollbar-gem 3.8.0
- Rails 7.1+ with
config.load_defaults "7.1" or later (verified on Rails 8.1.3)
- Not specific to Ruby version
Root cause
Rails builds the env value here — with precompilation on, this is [one_combined_regexp], not an array of names (railties lib/rails/application.rb):
# Rails::Application#env_config
"action_dispatch.parameter_filter" => filter_parameters,
# Rails::Application#filter_parameters (private)
if config.precompile_filter_parameters
ActiveSupport::ParameterFilter.precompile_filters(config.filter_parameters)
...
The extractor forwards it as extra scrub fields (lib/rollbar/request_data_extractor.rb:271):
def sensitive_params_list(env)
Array(env['action_dispatch.parameter_filter'])
end
And the Params scrubber destroys it (lib/rollbar/scrubbers/params.rb, build_fields_regex):
fields += Array(extra_fields)
...
Regexp.new(fields.map { |val| Regexp.escape(val.to_s).to_s }.join('|'), true)
Regexp.escape on a Regexp#to_s — e.g. "(?i-mx:(?i:passw)|(?i:token))" — produces an escaped literal that can never match a real parameter name.
Notably, Rollbar::Scrubbers::URL handles the same precompiled Regexp correctly (query string values in request.url do get scrubbed), which makes the params/session/cookies gap easy to miss: the URL looks scrubbed while GET/session leak the same values.
Reproduction
require 'rollbar'
require 'rollbar/request_data_extractor'
require 'rack'
require 'active_support/parameter_filter'
extractor = Object.new.extend(Rollbar::RequestDataExtractor)
def request_env(filters)
env = Rack::MockRequest.env_for('https://example.com/login?token=SECRET123&user_email=foo@bar.com')
env['rack.session'] = { '_csrf_token' => 'CSRFVALUE' }
env['action_dispatch.parameter_filter'] = filters
env
end
raw = [:passw, :email, :secret, :token]
precompiled = ActiveSupport::ParameterFilter.precompile_filters(raw)
# => [/(?i:passw)|(?i:email)|(?i:secret)|(?i:token)/]
data = extractor.extract_request_data_from_rack(request_env(raw))
data[:GET] # => {"token" => "******", "user_email" => "******"} (expected)
data[:session] # => {"_csrf_token" => "******"} (expected)
data = extractor.extract_request_data_from_rack(request_env(precompiled))
data[:GET] # => {"token" => "SECRET123", "user_email" => "foo@bar.com"} LEAKED
data[:session] # => {"_csrf_token" => "CSRFVALUE"} LEAKED
data[:url] # => "https://example.com/login?token=*********&user_email=***********"
# (URL scrubber handles the Regexp fine — only Scrubbers::Params is broken)
In a real Rails 7.1+ app the same thing is observable by raising from any controller action with a sensitive query param and inspecting the occurrence payload: the param appears unscrubbed in request.GET/request.params even though it is filtered in the Rails logs.
Suggested fix
In Scrubbers::Params#build_fields_regex, pass Regexp entries through instead of escaping their to_s:
fields.map { |val| val.is_a?(Regexp) ? val.source : Regexp.escape(val.to_s) }.join('|')
(or build a union with Regexp.union so per-entry flags survive). Alternatively, sensitive_params_list could delegate to ActiveSupport::ParameterFilter when available.
Related
Summary
Rollbar::RequestDataExtractorpicks up the app's Rails parameter filters fromenv['action_dispatch.parameter_filter']and merges them into scrubbing. Since Rails 7.1,config.precompile_filter_parameters(enabled byload_defaults "7.1"and later) makes Rails precompile that env value into a single combinedRegexpinstead of an array of names.Rollbar::Scrubbers::Params#build_fields_regexruns every entry throughRegexp.escape(val.to_s), which turns the compiled regexp into a literal string that matches nothing.Nothing raises — params, session, and cookie scrubbing silently degrades to the gem's small built-in
scrub_fieldsdefault list. Any Rails app onload_defaults "7.1"+ that relies onfilter_parametersbeing honored by Rollbar is sending those values unscrubbed in occurrence payloads.Environment
config.load_defaults "7.1"or later (verified on Rails 8.1.3)Root cause
Rails builds the env value here — with precompilation on, this is
[one_combined_regexp], not an array of names (railtieslib/rails/application.rb):The extractor forwards it as extra scrub fields (
lib/rollbar/request_data_extractor.rb:271):And the Params scrubber destroys it (
lib/rollbar/scrubbers/params.rb,build_fields_regex):Regexp.escapeon aRegexp#to_s— e.g."(?i-mx:(?i:passw)|(?i:token))"— produces an escaped literal that can never match a real parameter name.Notably,
Rollbar::Scrubbers::URLhandles the same precompiledRegexpcorrectly (query string values inrequest.urldo get scrubbed), which makes the params/session/cookies gap easy to miss: the URL looks scrubbed whileGET/sessionleak the same values.Reproduction
In a real Rails 7.1+ app the same thing is observable by raising from any controller action with a sensitive query param and inspecting the occurrence payload: the param appears unscrubbed in
request.GET/request.paramseven though it is filtered in the Rails logs.Suggested fix
In
Scrubbers::Params#build_fields_regex, passRegexpentries through instead of escaping theirto_s:(or build a union with
Regexp.unionso per-entry flags survive). Alternatively,sensitive_params_listcould delegate toActiveSupport::ParameterFilterwhen available.Related
Regexpsupport inscrub_fields; this bug is an instance of the same limitation, hit by default on modern Rails rather than opt-in.Scrubbers::Paramscould use a hardening pass.