Table of Contents

Sometimes the best bug discoveries don't begin with a target. Sometimes they begin with an unpaid toll bill.
It was a Friday night.
Like most people, I just wanted to get one annoying task out of the way before the weekend. I logged into my state's Turnpike Authority website to pay my toll bill, opened my password manager, clicked autofill, and signed in.
Incorrect username or password.
No big deal.
Password managers get out of sync occasionally.
I reset my password.
Tried again.
Incorrect username or password.
That was odd.
Maybe my password manager had generated a character the application didn't like. It happens. Some applications still have strange password restrictions they shouldn't have.
So I reset it again.
This time I intentionally chose something much simpler.
I signed in.
Incorrect username or password.
Three password resets.
Three failures.
At that point I stopped thinking like a customer.
I started thinking like a security researcher.
Calling customer support on a Friday night wasn't going to solve anything.
This is what I do every day.
So I launched Burp Suite, enabled the proxy, and walked through the entire password reset flow.
I wasn't expecting much.
Maybe an API error.
Maybe some JavaScript issue.
Instead, one response immediately caught my attention.
The server had just returned the SHA-256 hash of the password I had chosen.
I stared at the response for a second.
That... shouldn't be there.
Regardless of whether the hash itself could be abused, there was absolutely no reason for the server to expose authentication-related data back to the client.
It wasn't the vulnerability I was looking for.
But it was the first clue that something underneath this application wasn't behaving the way it should.
The only problem?
It still didn't explain why I couldn't log in.
So I kept digging.
I compared requests.
Compared responses.
Repeated the login flow over and over while watching every parameter moving between the browser and the backend.
Eventually something stood out.
The frontend JavaScript was sending one identifier.
The backend appeared to expect another.
It looked like someone had updated part of the authentication system but forgotten to update the frontend.
To test the theory, I intercepted the login request in Burp, changed the parameter manually, forwarded the request...
...and I was in.
No exploit.
No bypass.
The frontend was simply sending the wrong value.
At least I could finally pay my toll bill.
Most people would have closed the browser there.
Instead, curiosity got the better of me.
After paying my bill, I started exploring the rest of the application's functionality.
One feature immediately stood out.
Users who didn't have an account could still retrieve and pay outstanding tolls using a few pieces of information, including a vehicle's license plate.
That made me curious.
How exactly was this feature authenticating users?
I entered my own information and watched the traffic.
The answer appeared almost immediately.
The backend generated a JWT.
Interesting.
This wasn't simply looking up a toll balance.
It was actually authenticating users behind the scenes.
Now I wanted to understand how that authentication worked.
Earlier that evening I'd already discovered something important.
The frontend and backend weren't speaking exactly the same language.
What if that mistake existed here too?
I replayed the request.
Changed one parameter.
Forwarded it.
The response came back.
JWT.
But not for me.
For another account.
I remember sitting there for a few seconds trying to process what had just happened.
I hadn't bypassed authentication.
The application had authenticated me as someone else.
That changed everything.
Now it wasn't about exploitation.
It was about understanding the authentication flow.
Following the application's responses, I eventually discovered I could determine valid internal user identifiers through the workflow.
Those identifiers could then be supplied to the anonymous payment endpoint.
The application would happily return a valid JWT for that account.
A legitimate authentication token.
No username.
No password.
Just a broken authentication flow.
At that point, another thought crossed my mind.
I didn't need credentials.
I didn't need leaked passwords.
I just needed a license plate.
I stepped outside.
The first car I saw was parked only a few spaces away.
I entered the plate number.
A few moments later I was looking at another driver's account.
Names.
Addresses.
Vehicle information.
Account details.
That was enough.
I had demonstrated the impact.
I immediately stopped testing, saved my Burp logs, and went back inside.
There was nothing left to prove.
Looking back, that's probably the moment the severity really hit me.
Every car in a grocery store parking lot.
Every car sitting in traffic.
Every car parked outside an apartment complex.
The application trusted license plates far more than it should have.
By the time I finished mapping everything out, roughly two hours had passed.
What had started as a broken login had turned into a complete authentication failure.
The entire application trusted user-controlled information enough to issue valid authentication tokens for other accounts.
Later I would learn that this platform wasn't used by just one state.
It served multiple Turnpike Authorities across several states.
Potentially millions of drivers relied on it.
There was one problem.
It was Friday night.
There was no bug bounty.
No security.txt.
No vulnerability disclosure page.
No security contact.
Nothing.
So I waited until Monday morning.
I called customer support.
I didn't explain the vulnerability over the phone.
I simply said I had discovered what appeared to be a critical security issue that allowed unauthorized access to customer accounts and needed to speak with someone responsible for their IT systems.
Eventually the call reached a supervisor.
They asked if I could fax the details.
Fax them.
I couldn't help but laugh.
I politely explained that I wasn't comfortable sending sensitive security information through a fax machine and asked them to have someone from their technical team call me directly.
About thirty minutes later my phone rang.
On the line were members of the Turnpike Authority's IT department along with engineers from the vendor responsible for the application.
They were fantastic.
I walked them through the issue from beginning to end, explained exactly how I had discovered it, answered every question they had, and provided enough information for them to reproduce the issue safely.
Five days later...
It was fixed.
Did I receive a bounty?
No.
No Hall of Fame.
No reward.
Just a sincere thank you.
And honestly...
That was enough.
I wasn't hunting for money that Friday night.
I was trying to pay a toll bill.
Curiosity simply took over.
Sometimes that's where the best discoveries come from.
Lessons Learned #
This experience reinforced a few lessons that have stayed with me throughout my career.
A broken feature is rarely just one broken feature.
The failed login wasn't the real vulnerability.
It was simply the clue that led me toward something much bigger.
Always understand why something is broken.
Frontend and backend mismatches often reveal architectural issues hiding beneath the surface.
Curiosity is one of the most valuable tools a security researcher has.
If I had stopped after getting my login working, I never would have discovered the authentication issue.
At the same time, curiosity should always be balanced with ethics.
Once I demonstrated the impact, I stopped.
There was no reason to enumerate more accounts or collect more data.
The client didn't need a database full of victims.
They needed one clear demonstration, reproducible steps, and enough information to fix the problem.
Looking back, the strangest part wasn't the vulnerability itself.
It was how ordinary the entire story began.
If the login had worked the first time, I probably would have paid my toll in under a minute, closed the browser, and gone on with my weekend.
Instead, a broken login led to protecting the personal information of millions of drivers.
Not a bad outcome for a Friday night.