What Does a Bug Bounty Report for an IDOR in a Banking Application Look Like?
This detailed blog explains a real-world bug bounty case where the author found an Insecure Direct Object Reference (IDOR) vulnerability in a banking app. It includes a full walkthrough of how endpoint manipulation, token reuse, and API abuse led to the discovery, proof of concept, and eventual payout. The article also highlights the tools used, ethical hacking methodology, and lessons for aspiring bug bounty hunters.
Quick answer: A typical banking IDOR report shows that an API such as /transactions/<id> returns another customer's data when the ID is changed, because the server checks that you are logged in but not that the record is yours. This page cannot point to a verified named bank report, so it uses an illustrative example, a lab to practise, the fix and a report template.
Key takeaways
- IDOR (insecure direct object reference) means the server trusts an ID from the user without checking who owns the object. OWASP now files it under Broken Access Control, and APIs call it Broken Object Level Authorization (BOLA).
- Banks are high-value targets, so access control bugs in transaction, statement and profile APIs are serious. Most details of real bank findings stay private under programme rules.
- The example below is illustrative, not a real case.
- Practise on intentionally vulnerable apps such as OWASP crAPI and Juice Shop, never on a real bank.
- The fix is simple to state: check authorisation on the server, for every object, on every request.
What is an IDOR vulnerability?
An insecure direct object reference happens when an application uses a user-supplied value, such as an ID in a URL, to fetch a record, and does not check whether that user may see it. Authentication answers "who are you?". Authorisation answers "may you do this to this object?". IDOR is a failure of the second question.
Imagine a banking app that loads a statement through GET /api/statements/1042. If it returns statement 1043, which belongs to another customer, when you are logged in as the owner of 1042, the app has an IDOR. OWASP lists this class under A01 Broken Access Control, the top category in its Top 10.
Is there a real bug bounty report of IDOR in a banking application?
Yes, reports of this kind exist across the industry, but I cannot point you to one I have verified for a named bank, and I will not invent one. Programmes for banks are often private, and reports can stay confidential. If you want real public examples, browse disclosed reports on HackerOne's Hacktivity and read them critically: check the date, the programme, whether the issue was fixed and whether the reporter followed the rules.
What follows is a teaching example, clearly labelled as one. Bug bounty payouts vary widely by programme, so check each programme's published reward ranges.
Illustrative example (not a real case): statement download
This is a made-up scenario to show how the flaw looks and how it is reported.
- A tester has two accounts they created in a test environment the bank provided: Account A and Account B.
- Logged in as A, the app downloads a statement with
GET /api/v1/statements/5001and a bearer token for A. - Logged in as B, the tester finds B's statement ID,
5002. - Using A's token, the tester requests
/api/v1/statements/5002. - If the server returns B's statement, access control is missing. The tester stops there. One response is enough proof. They do not loop through other IDs to collect real customers' data.
That last step is the ethical line. Proof of the flaw needs one controlled test between your own two accounts. Enumerating a range of IDs to harvest other people's records is unauthorised access to personal data, even in a bounty, and may be an offence under India's Information Technology Act, 2000 as well as breaking the programme's rules.
Why does this happen in banking apps?
- Authorisation is checked at the front, not at the object. The gateway verifies the token, but the service behind it fetches any record by ID.
- Mobile and web clients hide controls, not rules. The app only shows your transactions, so developers assume the API will only be asked for yours.
- Predictable identifiers. Sequential numbers make guessing easy. Unpredictable IDs help, but they are not a fix.
- Many endpoints. Statements, receipts, beneficiaries, cards and support tickets each need their own check, and one is forgotten.
- Inconsistent microservices. One service enforces ownership and a newer one does not.
How do you practise finding IDOR legally?
Use targets built to be attacked.
- OWASP crAPI (completely ridiculous API) includes broken object level authorisation on purpose.
- OWASP Juice Shop has access control challenges in a shop setting.
- DVWA and your own small app, where you can read the code and see why it fails.
The method is the same each time:
- Create two users, A and B, and create some data for each.
- Browse as A and note every request with an object identifier in the path, query string or body.
- Replay a request as A with an ID that belongs to B. Use an intercepting proxy such as Burp Suite, or the browser's developer tools.
- If B's data comes back, you have an IDOR. Try other methods (PUT, DELETE) on your lab data to see whether writes are also unprotected.
- Write down the request, the response and the account used.
To see the web basics first, read what an IDOR vulnerability is, then the related story on a broken access control bounty. The OWASP Web Security Testing Guide has a test procedure for it.
How do you fix an IDOR?
- Enforce ownership on the server, every time. The query should include the logged-in user: fetch the statement where
id = :id AND customer_id = :current_user. If nothing matches, return 404 or 403. - Deny by default. New endpoints should refuse access until a rule allows it.
- Use a central authorisation layer instead of ad-hoc checks in each handler.
- Prefer unpredictable identifiers such as UUIDs as defence in depth, never as the only control.
- Write tests. For every endpoint with an object ID, add a test where user A requests user B's object and expects a refusal.
- Log and alert on one account requesting many different object IDs in a short time.
The OWASP Cheat Sheet Series has authorisation guidance for developers.
What does a good bug bounty report look like?
A good report lets a developer reproduce and fix the bug in minutes. Keep it factual and short.
Title: Statement API returns other customers' statements (BOLA)
Severity: High (access to another customer's financial data)
Summary: GET /api/v1/statements/{id} checks that the token is valid
but not that the statement belongs to the caller.
Steps to reproduce (test accounts A and B only):
1. Log in as A. Request GET /api/v1/statements/5001. Response: 200, A's data.
2. Log in as B. Note B's statement ID 5002.
3. Using A's token, request GET /api/v1/statements/5002.
4. Observe 200 with B's data.
Impact: Any logged-in user can read other users' statements if IDs are known or guessed.
Evidence: request and response (redacted), timestamps, account IDs.
Suggested fix: Add an ownership check in the query.
I did not access any other accounts' data.
Redact personal data in screenshots. Report through the programme's channel, and do not publish details until the owner agrees. If a bank has no bounty programme, look for its security contact, or for India, check the CERT-In site for how to report a vulnerability.
Common mistakes beginners make
- Testing a real bank without a programme or written permission. A bounty page is permission only within its scope.
- Pulling many records to "prove impact". One record from your own second account is enough.
- Reporting a guessable ID as a vulnerability when the server does check ownership. Always confirm the data returned really belongs to someone else.
- Posting a write-up before the bank has fixed the bug.
Next steps
To build the skills behind this kind of finding, see WebAsha's Web Application Penetration Testing (WAPT) course. For the earning side, read what bug bounty is and how it works.
Frequently Asked Questions
What's Your Reaction?
Like
0
Dislike
0
Love
0
Funny
0
Wow
0
Sad
0
Angry
0