September 19, 2026
Inactive. Not Gone.
What if a deactivated user never really left?
By Ameen Khan
2 min read
That is not a hypothetical. That is a bug I found sitting quietly inside a production system that had been running for years.
The Expected Behaviour
When a user is deactivated in a system, they are soft deleted โ not removed from the database, but marked as inactive. The expectation is simple: an inactive user should not be able to log in. They should not be able to access the system. They should not be able to place orders.
That is what the code was supposed to do. But that was not happening!
What Was Actually Happening
I was not looking for this bug. I was going through a few tickets, exploring parts of the system I had not worked in before, when I noticed something odd โ a deactivated user could still log in. Not just browse around either. They could access most features and, more critically, place orders. The most important flow in the entire system. Wide open.
A bug this significant, in a system this old, had simply never been caught.
Why It Happened
The login page accepted a username and password. For most users, their username is their email address โ so it looks and feels like a standard email login. Under the hood though, the SessionsController was looking up the user by their email field specifically.
The problem was that the sign-in form only submitted the username. It never submitted an email value. So when the controller went looking for email, it was always blank.
And because the inactive check was tied to finding the user by email โ if no user was found that way, the check never ran. The system then fell back, found the user by username, and let them straight in. No questions asked.
One field. Always blank. Inactive check never triggered. Years passed.
The Fix
Once the cause was clear, the fix had two parts.
First, the lookup โ the controller was corrected to find the user by username, which is what the form actually submits. No more searching by a field that was always blank.
Second, a small but important tightening โ the inactive check was extended to cover API calls as well. Because if an inactive user could log in through the front door, the API was another door worth closing.
Both gaps, sealed.
What This Left Me Thinking
This bug was not dramatic in its code. There was no complex logic, no clever exploit. Just a mismatch between what the form submitted and what the controller expected โ and an inactive check that quietly depended on the wrong thing.
The system had been in production for years. The bug had been there just as long.
Sometimes the most critical issues are not hiding in complex code. They are sitting in the gap between what you assumed was being checked and what was actually being checked.