From 2f13c07fbe4d9bcc8865bdb0d2c8c9dc2d667961 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 23 Sep 2026 07:52:44 +0000 Subject: [PATCH] Fix rate limits not normalizing submitted e-mail addresses (#40658) --- config/initializers/rack_attack.rb | 12 ++++++++---- spec/config/initializers/rack/attack_spec.rb | 12 ++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 853b99d32fd..b6d2fba85c3 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -60,6 +60,10 @@ class Rack::Attack def paging_request? params['page'].present? || params['min_id'].present? || params['max_id'].present? || params['since_id'].present? end + + def normalized_email + CanonicalEmailBlock.canonicalize_email(params.dig('user', 'email')) if params.dig('user', 'email').present? + end end Rack::Attack.blocklist('deny from blocklist') do |req| @@ -118,7 +122,7 @@ class Rack::Attack end throttle('throttle_password_resets/email', limit: 5, period: 30.minutes) do |req| - req.params.dig('user', 'email').presence if req.post? && req.path_matches?('/auth/password') + req.normalized_email if req.post? && req.path_matches?('/auth/password') end throttle('throttle_email_confirmations/ip', limit: 25, period: 5.minutes) do |req| @@ -127,14 +131,14 @@ class Rack::Attack throttle('throttle_email_confirmations/email', limit: 5, period: 30.minutes) do |req| if req.post? && req.path_matches?('/auth/confirmation') - req.params.dig('user', 'email').presence + req.normalized_email elsif req.post? && req.path == '/api/v1/emails/confirmations' req.authenticated_user_id end end throttle('throttle_auth_setup/email', limit: 5, period: 10.minutes) do |req| - req.params.dig('user', 'email').presence if (req.put? || req.patch?) && req.path_matches?('/auth/setup') + req.normalized_email if (req.put? || req.patch?) && req.path_matches?('/auth/setup') end throttle('throttle_auth_setup/account', limit: 5, period: 10.minutes) do |req| @@ -146,7 +150,7 @@ class Rack::Attack end throttle('throttle_login_attempts/email', limit: 25, period: 1.hour) do |req| - req.session[:attempt_user_id] || req.params.dig('user', 'email').presence if req.post? && req.path_matches?('/auth/sign_in') + req.session[:attempt_user_id] || req.normalized_email if req.post? && req.path_matches?('/auth/sign_in') end throttle('throttle_password_change/account', limit: 10, period: 10.minutes) do |req| diff --git a/spec/config/initializers/rack/attack_spec.rb b/spec/config/initializers/rack/attack_spec.rb index c7af11bea7c..98efa22dabb 100644 --- a/spec/config/initializers/rack/attack_spec.rb +++ b/spec/config/initializers/rack/attack_spec.rb @@ -71,6 +71,18 @@ RSpec.describe Rack::Attack, type: :request do let(:remote_ip) { '1.2.3.5' } let(:discriminator) { remote_ip } + describe 'throttle excessive confirmation e-mail requests by e-mail address' do + let(:throttle) { 'throttle_email_confirmations/email' } + let(:limit) { 5 } + let(:period) { 30.minutes } + let(:request) { -> { post path, params: { user: { email: email } } } } + let(:path) { '/auth/confirmation' } + let(:email) { 'foo@bar.com' } + let(:discriminator) { email } + + it_behaves_like 'throttled endpoint' + end + describe 'throttle excessive sign-up requests by IP address' do context 'when accessed through the website' do let(:throttle) { 'throttle_sign_up_attempts/ip' }