Make Devise Paranoid @StatelessCode
Make Devise Paranoid  @StatelessCode
Uploaded January 2023 | Updated September 2026, 2 weeks ago
Just because you're paranoid doesn't mean that everyone's not out to get you.

In our first pass of our epic to implement Devise, we wrote tests for the default Devise implementation where the user receives feedback on password reset requests, locks, and unlocks based on whether the User record associated with that email address exists or not.

The problem with this is that it divulges important information to non-authenticated entities about which users exist in the system and which do not. An attacker with a list of email addresses and passwords could use this information to make a brute force attack more fruitful and efficient. There are billions of public endpoints on the internet. If attackers find that your site is not vulnerable to a user enumeration attack, they will just probably move on to the next target or the next attack vector.

Devise comes with a configuration setting known as paranoid mode where the confirmable, recoverable, and unlockable modules are protected against divulging the user list. This doesn't affect registerable, so we will need to solve for that problem in a later video.

The actual application code change just involves uncommenting one line in our Devise configuration file. In the beginning of the video, I toyed with the idea of kind of doing artificial test-driven development and modifying all the tests to make them fail and then uncommenting the line to make the change. I ultimately decided against it. We went through the trouble of writing robust and meaningful tests from the beginning. This allows us to know exactly what breaks when we make the change. The robust test infrastructure allows us to make the change with confidence and then fix the new failures to account for our change in behavior.

There is a trade-off in the user experience, though. Because we aren't disclosing whether or not the user exists in our system, real non-malicious users no longer receive the warning when their account is about to be locked or feedback that the account is locked. It's an meaningful trade-off. We should always be mindful of actions that degrade the user experience. In this case, we deem the trade-off worthwhile, but add an item to the backlog to re-evaluate ways to make up for the changes to user experience in the future.


This video covers:
00:00:12 Introduction
00:02:58 Show paranoid language in Devise English locale file
00:04:01 Change config.paranoid to true and evaluate the new test failures
00:06:28 Fix ResetPasswordTest failures
00:11:49 Fix LockAndUnlockTest failures
00:24:34 Test changed functionality in browser
00:31:30 Add item to backlog to re-evaluate paranoid lock and unlock experience in the future, and talk about trade-offs between security and user experience
00:33:24 Review changes, clear RuboCop offenses, remove an unnecessary require, re-run full test suite
00:40:24 Commit, push, pull request, update project

#ruby #rails7 #rails #rubyonrails #rubygems #codecast #screencast #github #opensource #minitest #TDD #agile #NerdDice #DnD #roleplaying #softwaredevelopment #learntocode #tailwind #postgresql #rubocop #devise #turbo #controllers #views #selenium #capybara #systemtest #owasp #userenumerationattack

See other related StatelessCode videos:
- Why Test Driven Development youtu.be/AGXfZP-EhKo
- Write and Debug Happy Path System Tests for Devise Reset Password youtu.be/yz4DJ2Rtsh0
- Devise Reset Password Unhappy Path Tests and Refactoring youtu.be/ClmhgUNy_70
- Write Tests for User Locking and Unlocking and Finish the Devise Epic youtu.be/d-dHpSoU23Q

Resources that we relied upon for this solution:
- Devise Wiki - How To: Using paranoid mode, avoid user enumeration on registerable github.com/heartcombo/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable
- Testing for User Enumeration and Guessable User Account (OWASP-AT-002) wiki.owasp.org/index.php/Testing_for_User_Enumeration_and_Guessable_User_Account_(OWASP-AT-002)

This video is CC0 - No rights reserved. (YouTube doesn't allow this option when publishing.) All code is released under the UNLICENSE. Stateless Code denies the concept of "intellectual property". Copying is not stealing.
Make Devise ParanoidSubmit Contributions to Rails for the Authentication Generator and DocumentationCodecast: Create a RubyGem 81: Refactor ConvenienceMethods - Part 3NerdDice.com Retrospective 4 - It is a Long Way DownCreate a RubyGem 93: Refactor RuboCop to Enable New Cops by Default for the GemCodecast: Create a RubyGem 88: Add Ruby 3.1 to GitHub Actions and Update BundleGet Devise Working with Turbo in Rails 7Codecast: Getting Started with Rails 7 26: Fix Rich Text Fixtures and ValidationsInstall Ubuntu 24.04 LTS DesktopThe Prodigal Retro Returns!Mediocre Karaoke - Dust in the Wind by KansasDive into Agentforce and Prompt Builder
Stateless Code |

Make Devise Paranoid

SHARE TO X SHARE TO REDDIT SHARE TO FACEBOOK WALLPAPER