October 18, 2026
I Analyzed 12 IDOR-to-ATO Reports. The Email-Change Endpoint Wins.
Read-only IDORs get upvotes. Write-capable IDORs get accounts.

By Raj Namdev
7 min read
The 30-second version
I pulled the top IDOR and Account Takeover reports on HackerOne โ 47 titles mention both. I analyzed 12 for this piece: 5 full JSON, 2 team summaries, 5 dataset-cited.
The read-only leak is not what takes accounts. The write that takes accounts is the email-change / edit-user endpoint where the server trusts the
idyou send.
Four mechanisms_ cover nearly all of them. Five questions find them._
Why IDOR-to-ATO matters
Most IDOR writeups stop at "I changed id=1 to id=2 and saw someone's data."
That gets you a low payout and a lesson in enumeration. It does not get you an account.
The reports that end in takeover don't read data. They write identity. They change the email on someone else's account, add themselves as a secondary user, or pull an API token that lets them act as the victim. Then password reset does the rest.
No victim click. No XSS. Just one trusted parameter.
I started with the reddelexc HackerOne dataset โ TOPIDOR (254 entries) and TOPACCOUNTTAKEOVER (234 entries). 47 titles contain both IDOR and takeover language. I used 12 reports for this piece: 7 read in full or via the team summary, 5 cited from the dataset. Every claim below links to a report you can open, with verification status in Sources.
Where the bug lives
IDOR-to-ATO lives in the edit flows, not the view flows. Anywhere the app lets you modify who someone is by reference:
- a team member edit page carrying
invite-user.php?id= - an account settings POST carrying
idnext to the email - a profile update with
/IDin the path - a business user API
- an API app update with
application[id]
The shape repeats across every report here:
- Authenticated request.
- Object reference you control.
- Server checks you are logged in, not that you own the object.
- The write lands on the victim, and the reset flow finishes it.
Pattern 1 โ The email-swap
What it is: Change-email endpoint accepts a victim id. You set their email to one you control. Then forgot-password.
In the wild
- Atavist #950881. Logged in, opened
/cms/reader/account, changed email, intercepted. The request carriedidโ my user ID. Swapped to the test account's ID, forwarded. Victim's email changed. Then/forgotsent the reset to the attacker inbox. Full takeover, no interaction. The reporter notes IDs are sequential, so all accounts are enumerable. - MTN #1272478. Update-profile on
mtnmobad.mtnbusiness.com.ng. Captured the attacker request in Repeater, swapped/IDto the victim ID grabbed from a second browser. Changed theusernamefield (which holds the email) while leaving the attacker email in place. Then password reset. The reporter includes a video PoC.
Why it works:_ Email is identity. If write-access to email lacks an ownership check, the reset flow becomes a takeover primitive._
How to test
- Create two accounts.
- Change the email on A while proxying.
- Swap every ID-like field to B's ID.
- If the response is 200 and B's email changes in a second browser, stop and document.
- Then test if the reset goes to the new address.
Pattern 2 โ The edit-user login
What it is: The edit page for team members returns victim data, and the Save button logs you in as them.
In the wild
- CrowdSignal #915114.
GET /users/invite-user.php?id=(userid)&popup=1. Change the ID, the response shows the victim's email. Click Update Permissions and, per the report, you are logged in as the victim directly. The reporter states IDs range from00010006to19920500+. 202 upvotes, critical. The same hunter (bugra) also reported the Atavist bug in Pattern 1 (#950881); both were disclosed on 2020-11-18. - Supporting instance: MTN profile-update #1272478 doubles here โ the edit form both leaks and writes.
Why it works: The edit endpoint both discloses and acts. The frontend assumes that if you can load edit, you can submit edit. The backend never compares the session user to the target
id.
How to test
- Open any team user list.
- Right-click Edit, send to Repeater.
- Iterate IDs ยฑ10, then sequential scan a small range.
- Look for an email/name leak in the response.
- Then test the submit action with the swapped ID.
Pattern 3 โ The token pull
What it is: The IDOR doesn't change email. It returns a secret โ API token, Client Secret, session cookie โ that is the account.
In the wild
- Pressable #1695454.
POST /api/applicationswithapplication[id]. Swapped to a second account's app ID. The app moved accounts โ low impact. Then removed all params exceptapplication[id]+authenticity_token. The server errored with Name must be provided and printed the victim's app page containing the Client ID and Client Secret. Sequential IDs, so all apps are readable. The reporter says the leaked credentials could then be used against the collaborator endpoint to take over the account (that last step is argued in the report, not demonstrated). - Team-summary version: Starbucks Singapore #876300. An alternate site shared DB and cookie credentials with
card.starbucks.com.sg. CopiedPHPSESSIDfrom the alternate site, replayed it on the main site, saw user info, changed the password. Critical 9.0, 260 upvotes.
Why it works:_ Secrets are bearer. If read-access to a secret lacks an ownership check, you don't need to change anything._
How to test
- On any API app / integration page, create two apps.
- Update A, swap the ID to B.
- Strip optional params one by one.
- Error pages often print the object โ including secrets.
Pattern 4 โ The member-add
What it is: A business account lets the owner add secondary users. The IDOR lets you attach users from other accounts.
In the wild
- PayPal #415081.
POST businessmanage/users/api/v1/users. The owner could assign secondary users from other accounts. The new secondary user got access to that login's functions. $10,500, 797 upvotes โ the highest IDOR bounty in the dataset. PayPal's team summary says a business owner could assign secondary users from other accounts, giving unauthorized access to those users' logins; PayPal fixed it and found no evidence of abuse. - Dataset instance: Mars #2132183.
member_idchange to take over via POST, critical, 44 upvotes.
Same trust-the-member-reference failure, two programs.
Why it works:_ Multi-tenant membership checks ask_ "are you the owner?" but not "does this member belong to your tenant?"
How to test
- If the app has teams/orgs/invites, create org A + user X, and org B + user Y.
- Try adding Y to A by ID.
- Try changing
member_id,user_id,account_idin invite/add-member calls.
Watchlist โ The unchecked invite
One instance, not a pattern yet.
CrowdSignal #915110 โ no email checking on the invitation confirm link, 63 upvotes. It's a companion to #915114: same app, same reporter, disclosed the same day. The attacker confirms an invite meant for the victim.
Included because it shares the edit-user surface, but with one instance it does not meet the 3โ4 bar for a pattern. Watching for more.
From read to takeover: the escalation ladder
- ๐ข Low โ Read another user's order data. Example: WakaTime order info #2524562, 126 upvotes (closed N/A, no bounty).
- ๐ก Medium โ Read PII at scale. Example: Unikrn cashier enumeration #1966006, 232 upvotes (the program rated it High).
- ๐ High โ Write another user's data. Examples: HackerOne GraphQL delete-licenses #2122671, 391 upvotes; PayPal secondary-user add #415081, $10,500 โ a write that crosses tenants.
- ๐ด Critical โ Full ATO, no interaction. Examples: #915114, #950881, #1272478, #876300 above. HackerOne session-cookie #745324 ($20,000, 1,642 upvotes) sits here as the ceiling โ a session cookie exposed by human error and reused to reach a Security Analyst's account (listed High, CVSS 8.3).
The jump from High to Critical is almost always password reset or session replay after the IDOR write. Test the reset immediately after any successful write.
The report that made it click
Bugra's CrowdSignal report #915114 is short: a four-step list and one screenshot.
He clicks Edit on a teammate. The request is invite-user.php?id=19920465. He changes the number. The response shows another user's email. He clicks Update Permissions. Per the report, he is logged in as that person.
No WAF bypass. No JavaScript. No chain of five bugs. Just id trusted.
What stuck with me: the range. 00010006 to 19920500. Roughly 19.9 million possible IDs on one endpoint (the report doesn't show that every one is a live account). The hunter didn't need to be clever after the first swap โ just persistent. And the same hunter reported the same bug class on Atavist, disclosed the same day, and got ATO again.
The technique transfers. The apps don't learn from each other.
That is why I test edit-user first on every new target now. Not search, not profile view. Edit.
5 questions to run on every endpoint
- Does this request carry an
id,user_id,member_id,application[id], or path/IDthat decides whose object I touch? - If I swap it to my second account's ID, does the response leak email, token, or secret โ or does the write land?
- If the write lands on email/username, does forgot-password now send to my inbox?
- If there's an error, does the error print the victim object (Name must be provided, and here is the Client Secret)?
- Are IDs sequential or guessable, and does invite/confirm bind to email or just token?
Run those on edit-user, change-email, team-invite, API app update, and order/profile update. You cover all four patterns.
What to remember
Read-only IDOR gets upvotes. Write-capable IDOR gets accounts. Start with the email field.
Next: XSS-to-ATO โ where HttpOnly doesn't save you. Mining stored XSS chains that end in the same change-email plus reset step.
Sources
12 linked, status labeled. 5 full JSON + 2 team summaries verified live, 5 dataset-cited.
- IDOR editing users โ ATO no interaction, CrowdSignal โ #915114 โ full JSON verified, critical, 202 upvotes
- IDOR editing email โ ATO, Atavist โ #950881 โ full JSON verified, critical, 50 upvotes
- IDOR profile update โ ATO no interaction, MTN โ #1272478 โ full JSON verified, critical, 34 upvotes
- IDOR API token leak โ ATO, Pressable/Automattic โ #1695454 โ full JSON verified, critical, 58 upvotes
- Singapore ATO via IDOR, Starbucks โ #876300 โ team summary verified, critical 9.0, 260 upvotes
- IDOR add secondary users, PayPal โ #415081 โ team summary verified, high 7.1, $10,500, 797 upvotes
- ATO via leaked session cookie, HackerOne โ #745324 โ full JSON verified, $20,000, 1,642 upvotes
- No email check on invite โ ATO, CrowdSignal โ #915110 โ dataset-cited, body not live-fetched, 63 upvotes
- IDOR member_id โ ATO, Mars โ #2132183 โ dataset-cited, body not live-fetched, 44 upvotes
- IDOR order info, WakaTime โ #2524562 โ dataset-cited, body not live-fetched, 126 upvotes
- IDOR user enumeration, Unikrn cashier โ #1966006 โ dataset-cited, body not live-fetched, 232 upvotes
- IDOR delete licenses via GraphQL, HackerOne โ #2122671 โ dataset-cited, body not live-fetched, 391 upvotes
Dataset: reddelexc/hackerone-reports โ TOPIDOR (254 entries) + TOPACCOUNTTAKEOVER (234 entries). 47 titles mention both. 5 full JSON + 2 team summaries verified live, 5 dataset-cited with status labeled.