Most writeups make a bug look inevitable: run the right tool, notice the perfect parameter, find the vulnerability. That is not how this test felt.
I had no secret trick. I followed the application, made a few weak assumptions, went down paths that returned nothing, and kept comparing what the server accepted with what it should have accepted.
Before touching the target
This was a normal, authorized pentest. The host redacted.in was inside the agreed scope and the rules allowed non-destructive web testing.
I wrote down three limits before I started:
- Stay inside the listed host and testing window.
- Use only accounts and data created for the test.
- Stop as soon as there is enough evidence to prove a security issue.
An open port is not permission. Scope is the first technical control in a legal pentest.
I started quietly—and found almost nothing.
I checked Shodan for old services and exposed hosts. I also used simple Google searches such as site:redacted.in and looked for public documentation, login pages, and forgotten files.
The result was underwhelming: no useful subdomains, no leaked documents, and no interesting cached pages. That was still a result. It told me to stop forcing passive recon and move to the active checks allowed by the engagement.

Then Nmap gave me one clue: HTTP.
I ran a small, scope-limited service scan. Port 80 was open and serving HTTP. That sounds ordinary—and it is—but it changed the next question from “what is exposed?” to “what does this web application trust?”
$ nmap -sV -p 80 redacted.in
80/tcp open httpI opened the site in a browser before doing anything aggressive. It redirected into a working application with login and registration flows. The response headers did not reveal an obvious vulnerable version, so version hunting was not going to carry this test.

The obvious checks went nowhere.
I checked robots.txt, common public files, page source, JavaScript filenames, and a short list of likely paths. I found a few normal application routes but nothing sensitive.
I also spent time looking for a hidden admin panel. That assumption came from the site’s structure, not from evidence. It was a dead end. I stopped expanding the path list when the responses became repetitive and returned to the application itself.
Normal responses. No secrets or useful comments.
Mostly the same not-found page. No lead.
No reliable vulnerable component to validate.
I was searching for a dramatic entry point. The useful clue was inside a normal authenticated feature.
I stopped guessing and used the site normally.
I created two test accounts—Account A and Account B—because the rules allowed it. Then I clicked through each feature while Burp Suite recorded the traffic.
For every request, I noted four things: the action, the endpoint, the identifier being sent, and the response. A normal “view order” action stood out because the request included a predictable numeric object ID.
GET /api/orders/1042→200 OKACCOUNT B→GET /api/orders/1088→200 OKA numeric ID is not automatically a bug. The important question was whether the server checked that the signed-in user owned the requested object.
One changed number changed the result.
I sent Account A’s order request to Burp Repeater. First, I replayed it unchanged to confirm the response was stable. Then I changed only the order ID to the ID created by Account B.
The session cookie still belonged to Account A. The server returned 200 OK and included Account B’s sanitized order data. The application had authenticated the user, but it had not authorized access to that specific object.

What is IDOR?
Insecure Direct Object Reference happens when an application accepts an object identifier—such as an order ID—but fails to verify that the current user is allowed to access that object.
I proved the minimum and stopped.
I repeated the comparison once in the opposite direction using only my two controlled accounts. That confirmed the behavior was consistent. I did not enumerate other IDs, download real user data, or automate the request.
A requests A’s object
200 OKA requests B’s object
200 OK — FAILA requests B’s object
403 OR 404I saved the original request, the single changed value, both sanitized responses, timestamps, and the two test account IDs. That was enough evidence for a reproducible report.
Why this mattered
An authenticated user could access an object owned by another user. Depending on the real fields behind that endpoint, this could expose personal or transaction data. I reported only the impact I had actually demonstrated.
What the application should do
- Check object ownership or permission on every server-side request.
- Deny access by default when the user-object relationship is missing.
- Add authorization tests for cross-account access.
- Use unpredictable identifiers as defense in depth—not as a replacement for authorization.
- Review nearby endpoints that use the same object-access pattern.
What I took away from it
- Nothing found is still information.
Passive recon did not fail. It helped me choose a better next step.
- An open port is context, not a finding.
Port 80 only pointed me toward the application and its trust boundaries.
- Normal features deserve attention.
The bug was not hidden in an exotic endpoint. It lived inside an everyday action.
- Change one thing at a time.
Burp Repeater made the authorization failure easy to explain because only the object ID changed.
- Prove less, document more.
Two controlled accounts and one manual comparison were enough. More access would only create more risk.
Port 80 did not reveal the bug. It gave me a door. The finding came from slowing down and asking what every ordinary request was allowed to see.