Resetting the Admin’s Password Without Touching Their Inbox
By Sid — Cybersecurity Engineer & Pentester
Resetting the Admin’s Password Without Touching Their Inbox
Photo by Zulfugar Karimov on Unsplash
By Sid — Cybersecurity Engineer & Pentester
**Disclosure note: **This was found during an authorized penetration test Target name anonymized as “PayrollSuite” below at the client’s/program’s request.
Hey everyone, it’s been a while since my last write-up — work got in the way for a bit — but I’m back and planning to start posting on Medium again. Let’s jump into it.
Password reset flows are one of my favorite places to poke around during a pentest. They’re security-critical by definition, they usually involve some kind of token, and developers love to take shortcuts with “just a temporary ID, it’s fine.” This one — found during a gray-box engagement against an HR/payroll platform I’ll call PayrollSuite — is a perfect example of that shortcut going very wrong.
The flow
PayrollSuite’s “forgot password” feature is fairly standard on the surface:
- User requests a password reset (via email or SMS).
- Backend generates a reset link and emails it.
- User clicks the link, lands on a reset page, sets a new password.
Nothing about this screams “vulnerable” yet. Let’s intercept the first request and see what’s actually happening under the hood.
Following the token

Figure 1. Password reset page
Kicking off a reset request from my own test account and catching it in Burp, the first thing that stood out was how the identifier behaved: every single request generated a new ID, one number higher than the last. In this app, that counter lives in a field called idToken.
That alone is a red flag. An incremental, predictable identifier means an attacker doesn’t need to guess anything — they just need to watch their own value and count up (or down) from there. That kind of weak, non-random token is exactly what turns a password reset flow into a wide-open door: intercept or fabricate someone else’s reset link, and you’ve effectively hijacked their recovery process.
Intercepting the reset request
Here’s the response to my own reset request:
HTTP/2 200 OK
Date: Mon, 15 Sep 2025 18:17:56 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 225
Vary: Origin,Origin
Server: Microsoft-IIS/10.0
Api-Supported-Versions: 1.0
Access-Control-Allow-Origin: https://qa.payrollcloud.io
Access-Control-Allow-Credentials: true
X-Powered-By: ASP.NET
{
"idToken": 459,
"idCuenta": 3,
"idUsuario": 339,
"token": "6c33aa-e4a7-46ab-9487-bb72a3f499",
"codigo": "A8jfB4MKQHHAf/PQVxQ==",
"usuario": "admin.admin",
"expiro": false,
"aplicado": false,
"clave": "mjrl5JwSC8vKJCtP432YcA=="
}
That idToken: 459 is what eventually gets baked into the reset link sent by email, wrapped in a tracking redirect:
https://<tracking-redirect>/L0/https:%2F%2Fqa.payrollcloud.io%2FPayrollSuite%2F%23%2Flogin%2F459/...

Figure 2. The password reset email.
So the entire security of “did this reset request belong to you” comes down to whoever holds a URL containing that one number.
Turning it into account takeover
At this point the question answers itself: what happens if I request a reset again, but this time hand the API 460 instead of 459? That ID happened to belong to the platform's super-admin account.
The result: the password reset went through completely — no email sent to the account owner, no confirmation step, no secondary check of any kind. The system never verified that the token actually belonged to the session or user making the request, and it never confirmed the action through the “official” channel (email, OTP, anything). Possession of the number was all it took.
That’s what makes this more than a theoretical IDOR — there’s no binding between the token and its rightful owner, no single-use enforcement, and no meaningful expiration. Put together, that’s a direct route to taking over privileged accounts, with zero trace left for the actual owner and no notification that anything happened.
Logging in from there was trivial — same URL pattern, new number:
Logging in as admin
With the password reset through the manipulated idToken, logging in was trivial:

Figure 3. Logged in as admin.
https://qa.payrollcloud.io/PayrollSuite/#/login/460
Why this is worse than it looks
A few things stack together here to make this particularly bad:
- The identifier is sequential and enumerable. Anyone who has ever triggered a password reset can infer the rough range of valid
idTokenvalues just by looking at their own. - There’s no binding between the token and the requester. The backend never checks “is the person submitting this new password the same person/session that originally asked for the reset.”
- There’s no secondary verification. No re-sending the confirmation link, no OTP, no session check — possession of the number is the authorization.
- It’s not rate-limited. Nothing stopped scripting this into a loop and resetting a batch of accounts, admin or not, in seconds.
Impact
- Full account takeover of any user, including administrators, without needing access to their inbox, phone, or any credentials.
- Because this is a payroll/HR platform, an attacker landing in an admin account gets access to employee personal data, salary information, and organizational configuration — a textbook path to a serious data breach.
- Trivially scriptable: this isn’t “found one admin token by luck,” it’s “every single reset request generates a target.”
This one landed as Critical — no privileges required, minimal complexity, and a direct path to full compromise of the most sensitive account type on the platform.
The fix
- Never rely on the identifier alone as proof of authorization. The reset token must be validated against the specific request/session that generated it — not just “does a record with this ID exist.”
- Use unpredictable, high-entropy tokens (cryptographically random, sufficiently long) instead of sequential integers. Guessing the next token should be computationally infeasible, not a two-second manual test.
- Bind the token to a single-use, time-limited window, and invalidate it the moment it’s used or a new one is requested for the same account.
- Require the actual verification step to matter. If there’s an email or SMS involved, the flow shouldn’t be completable without whatever that channel provides (e.g., a signed, unguessable link — not just an ID that’s echoed back).
- Rate-limit and monitor reset attempts per account and per IP, and alert on sequential/enumerative access patterns against reset endpoints.
Takeaway
“It’s just an internal ID” is one of the most dangerous assumptions in web security. If that ID shows up anywhere in a client-facing request — a URL, a JSON body, a header — it’s not internal anymore, and an attacker will treat it as an input to fuzz. Password reset flows in particular deserve the same scrutiny as the login form itself, because functionally, that’s exactly what they are: an alternate way in.
메타데이터
- post_id
- 4a14bf805838
- slug
- resetting-the-admins-password-without-touching-their-inbox-4a14bf805838
- url
- https://medium.com/@sidblog/resetting-the-admins-password-without-touching-their-inbox-4a14bf805838
- canonical_url
- https://medium.com/@sidblog/resetting-the-admins-password-without-touching-their-inbox-4a14bf805838
- author_url
- https://medium.com/@sidblog
- status
- ok
- fetched_at
- 2026-09-03 07:23:47