Skip to content

Fix race condition vulnerability, by ensuring the unconfirmed_email is always saved#5784

Merged
carlosantoniodasilva merged 5 commits intoheartcombo:mainfrom
grantcox:email-confirmation-race-condition-vulnfix
Mar 16, 2026
Merged

Fix race condition vulnerability, by ensuring the unconfirmed_email is always saved#5784
carlosantoniodasilva merged 5 commits intoheartcombo:mainfrom
grantcox:email-confirmation-race-condition-vulnfix

Conversation

@grantcox
Copy link
Copy Markdown
Contributor

@grantcox grantcox commented Jul 7, 2025

Fixes #5783

Comment thread test/integration/confirmable_test.rb
Copy link
Copy Markdown

@runephilosof-abtion runephilosof-abtion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another way to solve this, would be to use transactions and locking for update.
However, that might be a problem for some database backends?
Anyway, transactions have not been used anywhere else in Devise and the approach in this PR works.

Comment thread test/integration/confirmable_test.rb Outdated
Comment thread test/integration/confirmable_test.rb Outdated
Comment thread test/integration/confirmable_test.rb Outdated
Comment thread test/integration/confirmable_test.rb Outdated
Comment thread test/integration/confirmable_test.rb Outdated
@grantcox grantcox force-pushed the email-confirmation-race-condition-vulnfix branch from cfa56a4 to 502ed42 Compare August 7, 2025 18:27
@grantcox
Copy link
Copy Markdown
Contributor Author

grantcox commented Aug 7, 2025

Thank you for the feedback @runephilosof-abtion , your changes were very helpful and I've merged them all now

grantcox and others added 2 commits February 4, 2026 10:07
…s always saved even if the submitted value is the same as the in-memory model's state
Co-authored-by: Rune Philosof <57357936+runephilosof-abtion@users.noreply.github.com>
It appears Mongoid differs from AR in that even if you're calling
`will_change!` on an attribute to "force" it to see (and persist)
changes, and it gets set to `changed_attributes` so it knows it's
technically "changed", the model's `changes` which are based on
`attribute_changed?` don't include the field because it didn't actually
"change" from its original value, so it doesn't get persisted by
Mongoid.

This was causing the new test for the confirmable race condition issue
to fail, because `will_change!` wasn't forcing the "change" to be
persisted in Mongoid.

This is a workaround for it, by setting `changed_attributes` directly to
`nil` (could be any value like `__devise-force-change__`) it makes
Mongoid see the changes and persist them.
@carlosantoniodasilva carlosantoniodasilva merged commit 0252777 into heartcombo:main Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Confirmable "change email" vulnerability - race condition permits user to confirm email address they have no access to

3 participants