From 9ca680de0246cfad84e7e6dba9cfb370fb1277b2 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Tue, 20 Oct 2026 08:57:40 -0700 Subject: [PATCH] Sign the browser out when its new session is refused after a password change If the password changes again between this browser's change and its new session, that session is refused, and the browser is sent to sign in instead of an error. (cherry picked from commit a476cbfa24e9863fb9e9e555cb45de6183db78e7) --- app/controllers/users/profiles_controller.rb | 3 +++ test/controllers/users/profiles_controller_test.rb | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/app/controllers/users/profiles_controller.rb b/app/controllers/users/profiles_controller.rb index 6b30b744..4f5ab314 100644 --- a/app/controllers/users/profiles_controller.rb +++ b/app/controllers/users/profiles_controller.rb @@ -18,6 +18,9 @@ class Users::ProfilesController < ApplicationController else redirect_to user_profile_url, alert: update_alert end + rescue ActiveRecord::RecordInvalid + # The password changed again before this browser's new session could start, and that change signed it out. + redirect_to new_session_url end private diff --git a/test/controllers/users/profiles_controller_test.rb b/test/controllers/users/profiles_controller_test.rb index 49fcb3da..035318db 100644 --- a/test/controllers/users/profiles_controller_test.rb +++ b/test/controllers/users/profiles_controller_test.rb @@ -43,6 +43,16 @@ class Users::ProfilesControllerTest < ActionDispatch::IntegrationTest assert_equal 1, users(:david).sessions.count end + test "changing the password signs this browser out when it changes again before its new session starts" do + User.stubs(:uncached).returns(BCrypt::Password.create("someone else's secret", cost: BCrypt::Engine::MIN_COST)) + + assert_changes -> { users(:david).sessions.count }, to: 0 do + put user_profile_url, params: { user: { password: "a new secret123456", password_challenge: "secret123456" } } + end + + assert_redirected_to new_session_url + end + test "changing the password gives this browser a new session, so a copy of its cookie stops working" do copied_cookie = cookies[:session_token]