October 24, 2026
My Bug Bounty Comeback: Two Findings, Two Lessons Learned
Hi everyone! ๐
By DOD cyber solutions
5 min read
I'm back with another write-up after a long break from bug bounty hunting.
Due to personal reasons, I had to step away from bug bounty hunting for a while. During that break, the security landscape continued to evolve. One of the biggest changes I've noticed is the growing role of AI in cybersecurity.
AI is changing how security researchers discover vulnerabilities, automate testing, and analyze applications. At the same time, finding valid bugs and standing out as a researcher can feel more challenging than ever.
After experiencing this myself, I decided to start hunting again.
Getting Back into Bug Bounty Hunting
I started with an old public program on Bugcrowd.
My main goal wasn't to earn a bounty immediately. Instead, I wanted to rebuild my confidence, refresh my testing skills, and get back into the bug bounty mindset after a long break.
During my testing, I identified two potential security issues.
Unfortunately, neither resulted in a bounty:
- Finding 1: IDOR โ Closed as Duplicate (P4).
- Finding 2: GraphQL User Enumeration โ Closed as Informational (P5).
Although the results weren't what I hoped for, both findings taught me valuable lessons about vulnerability validation, impact, and severity.
Let's look at what I discovered.
1. IDOR (Insecure Direct Object Reference)
What Is IDOR?
IDOR stands for Insecure Direct Object Reference. It is a type of broken access control vulnerability.
In simple terms, IDOR occurs when an application allows a user to access or modify another user's data by manipulating an object identifier in a request, without properly verifying whether the user has permission to perform that action.
For example, imagine an e-commerce website where every user's shopping basket has a unique identifier.
If the application fails to verify ownership of the basket, one user might be able to access or modify another user's basket by changing the identifier in an HTTP request.
That's the basic idea behind IDOR.
Understanding the Target Functionality
For this example, let's use a fictional e-commerce website: ecommerce.co.tk.
Like most e-commerce websites, it allows users to add products to their shopping baskets, update quantities, and remove products before purchasing.
Each basket has a unique identifier.
The important security question is:
Does the application verify that the currently authenticated user owns the basket they are trying to access or modify?
A unique identifier alone does not provide access control. The server must still verify authorization for every relevant request.
How I Tested It
I used two accounts that I controlled: User 1 and User 2.
Step 1: Create two test accounts
I registered two accounts so I could compare how the application handled requests belonging to different users.
Step 2: Create a basket for User 1
I logged in as User 1, added a few products to the basket, and captured the relevant HTTP request using Burp Suite.
I examined the request and identified the basket's unique identifier.
Step 3: Create a basket for User 2
Next, I logged out and logged in as User 2.
I added products to the second basket and captured the corresponding request.
Step 4: Test access control
While authenticated as User 2, I replaced User 2's basket identifier with User 1's basket identifier in the relevant request.
I then tested the applicable operations:
- Create: Add items to the basket.
- Read: Retrieve basket information.
- Update: Modify basket contents.
- Delete: Remove basket contents or items, where supported.
The application returned successful HTTP responses, including 200 OK.
However, an HTTP 200 OK response alone does not prove that a vulnerability exists. I needed to verify whether the application had actually performed an unauthorized action.
Step 5: Verify the impact
I logged back into User 1's account and inspected the basket.
I confirmed that the changes made while authenticated as User 2 had affected User 1's basket.
This confirmed that the application was not correctly enforcing basket ownership for the tested operation.
Why Was It Classified as P4?
The report was closed as a duplicate with a P4 severity classification.
One possible factor affecting the practical severity is the difficulty of obtaining another user's basket identifier. However, a random or unpredictable identifier does not replace proper authorization checks.
The severity of an IDOR depends on several factors:
- What information or functionality can be accessed?
- Can another user's data be modified or deleted?
- Is the identifier exposed through application functionality or other sources?
- Can the issue be exploited reliably?
- What would the actual consequences be for the affected user?
In this case, I demonstrated that one account could modify another account's basket.
However, the report was marked as a duplicate, meaning the same underlying issue had already been reported. A duplicate closure does not necessarily mean the finding was invalid.
My takeaway: Never rely on an object's unique identifier as a security mechanism. Always test whether the server enforces authorization for the requested resource and action.
2. GraphQL User Enumeration
My second finding involved a GraphQL endpoint on the same target.
What Is GraphQL?
GraphQL is a query language for APIs that allows clients to request specific data from a server.
Unlike a traditional REST API, a GraphQL API commonly exposes a single endpoint through which clients can execute different queries and mutations.
During my testing, I discovered that the target's GraphQL introspection feature was enabled.
Introspection allows clients to inspect an API's schema and discover information about its available types, fields, queries, and mutations, depending on the server's configuration.
However, enabled introspection is not automatically a vulnerability. Its security significance depends on the information exposed and the application's threat model.
Finding an Email Enumeration Function
While exploring the GraphQL API, I examined the available operations and tested the account creation marketing preference functionality.
I found a query that appeared to check whether an email address was associated with an account.
The request was similar to the following:
query {
accountCreationMarketingPreferences(email: "test@example.com")
}query {
accountCreationMarketingPreferences(email: "test@example.com")
}This is a reformatted GraphQL representation of the operation I tested. The actual request may use a different structure depending on the API's implementation.
What Did I Observe?
I supplied an email address and examined the server's response.
The operation appeared to reveal information about whether the supplied email address was associated with an account.
If an unauthenticated or unauthorized user can distinguish registered email addresses from unregistered ones, the behavior may constitute user or account enumeration.
For example, an attacker could potentially use this information to identify existing accounts.
However, the security impact depends on the exact responses, whether authentication is required, any rate limiting, and what information is actually disclosed.
Why Was It Classified as P5?
The report was closed as Informational (P5).
Although the behavior could reveal whether an account exists, the demonstrated impact was limited.
I had not established any additional consequences, such as account compromise, unauthorized access, or exposure of sensitive account information.
Email enumeration can still have security implications, including targeted phishing and privacy concerns. Nevertheless, some programs classify account-existence checks as informational when the impact is limited or the behavior is expected.
My takeaway: Discovering an interesting API behavior is only the first step. To make a strong vulnerability report, I need to demonstrate what an attacker can actually achieve and explain why that behavior matters.
Lessons Learned from These Findings
Even though neither finding resulted in a bounty, the experience helped me identify areas where I can improve.
1. Focus on Impact, Not Just Functionality
A request returning 200 OK does not automatically indicate a vulnerability.
I need to verify whether unauthorized access or modification actually occurs and clearly explain its consequences.
2. Understand the Difference Between Duplicate and Informational
A duplicate means the same underlying vulnerability has already been reported.
An informational classification generally means the behavior does not meet the program's threshold for a valid, actionable security issue.
Neither outcome means that testing was a waste of time.
3. Go Beyond Discovering API Operations
Finding GraphQL queries, mutations, or enabled introspection can help me understand an application's functionality.
The next step is to investigate authorization, data exposure, business logic, and the actual security consequences of those operations.
4. Keep Learning and Keep Hunting
Coming back after a long break isn't easy.
The tools change, techniques evolve, and expectations around vulnerability reports can be demanding. But every test, rejection, duplicate, and informational finding can help me improve my methodology.
I want to focus on better validation, clearer impact demonstrations, and more meaningful vulnerability reports rather than simply increasing the number of findings.
Final Thoughts
Getting back into bug bounty hunting has reminded me that success is not just about finding vulnerabilities. It is also about understanding them, validating their impact, and communicating the risks clearly.
These two findings didn't result in a bounty, but they gave me an opportunity to learn and improve.
I'm starting again, rebuilding my confidence, and continuing the journey.
A duplicate is not the end. An informational finding is not the end. The important thing is to learn, improve, and keep going.
Thanks for reading! โค๏ธ
If you're also returning to bug bounty hunting after a break, share your experience in the comments. Let's learn from each other.
Happy hunting! ๐