July 4, 2026
How I Do Recon in 2026: No Subdomains, No Wordlists, Just the App
The place the bugs live is already open in your browser. Most hunters spend hours looking everywhere else.

By Muhammad Haider Tallal
12 min read
By Muhammad Haider Tallal
Broken access control is almost always there.
IDORs. Privilege escalation. Role confusion. Horizontal access failures.
Almost every app has at least one. They're almost always reportable. And they often pay.
Here's the part most hunters miss: the place those bugs live is already sitting open in your browser. You don't need a scanner to find it. You need to understand the app in front of you.
That's what this article is about:
The way I actually start a target in 2026. No subdomain enumeration. No wordlist spam. No JavaScript collectors. Just the app, my proxy, and my head.
Let me walk you through it.
Why I Skip Classic Recon at the Start
The Two Words Every Hunter Repeats
In recon, most hunters talk about two things: asset discovery and content discovery. They treat those two like they're the whole job.
Asset discovery means finding a new surface. A new subdomain, a new host, a new thing the program forgot about.
Content discovery means finding a specific thing in a specific place. A hidden endpoint, a backup file, an old route, an undocumented parameter.
Why I Skip Both at the Start
I skip asset discovery because I don't need more assets right now. They'd just distract me. The host I'm hacking on is already in front of me in the browser. I picked it when I picked the target. And if the app talks to another host, my proxy shows me the moment the request fires. I don't need a scanner to tell me what the app is doing when the app is already telling me as I use it.
I skip content discovery for a different reason. It only makes sense when you know what you're looking for and why. Before I understand the app, I don't know that. I'd be fuzzing for directories I have no reason to want, or brute-forcing parameters I couldn't explain the purpose of.
If I can't answer why am I searching here and what am I searching for, there's no reason to search.
When Targeted Discovery Earns Its Place
Later, that changes. Say I have an authentication issue that only becomes critical if I can chain it with an open redirect, and I don't have one yet. Now I go do content discovery on this exact host, looking for parameters that take a redirect URL. Or I'm hunting for data exposure and I need a backup file to prove impact. Now I go look for one.
Targeted. One specific place. One specific reason. Driven by my understanding of the app, not by habit.
That's the difference. Content discovery at the start is guessing. Content discovery after understanding is hunting.
The bugs are already sitting open in your browser. The faster you start looking at what's in front of you, the faster you find them.
First, I Just Use the App
Before I explain anything, I just use the app. Ten minutes.
I log in. I click around. I hit every main feature I can find without thinking too hard about it. I don't test anything. I don't change anything. I use it like a normal user, and my proxy sits in the background recording everything.
Ten minutes later I have two things: a feel for what the app actually does, and a clean pile of real traffic sitting in my Caido HTTP history.
Then I split the platform.
Split the Platform Into Pieces
Every Platform Splits Into Surfaces
A normal platform with one kind of user splits into two pieces: the frontend, and the backend API. Everything the browser renders is one surface. Everything the requests talk to is another.
If the platform ships more than one kind of app, the count multiplies, but only when those are genuinely separate apps. A partner portal on its own URL with its own frontend and its own API. An admin panel built on its own stack, not a page inside the main one.
User app plus partner portal, each with its own frontend and API. That's four pieces. Add an admin panel in its own stack, six.
Count Apps, Not Roles
Here's the thing nobody catches: the multiplier is not the number of roles. It's the number of separate apps the platform ships.
You can have ten user roles and still live on one frontend and one API. That's two bases, not twenty. Same route, same backend, just different access decisions happening inside.
Roles matter for what you test inside each piece. Surfaces matter for how many pieces you split into. So when you count, count apps, not roles.
What the Split Buys You
The moment you run that split, everything changes. You stop looking at a target and start looking at a finished list of surfaces. A photo-sharing platform with a user account and a partner dashboard isn't one thing. It's four. Four places where access control can fail. Four places where the developer probably didn't remember to enforce the same rules across every boundary.
Every piece gets its own attention. Every piece gets its own session. You never mix them up, and you never forget one.
Focus before chaos.
Ask How, Why, and When
Most hunters understand how an app works. They read the docs, they click around, they figure out the features. That's the floor. It's not enough. You need three questions answered.
How Does the Feature Work?
Everyone gets there. That's the easy one.
Why Does It Work?
Why is this field here? Why does this endpoint return what it returns? Why does this user see this button and the other user doesn't? Why is there an admin rule at all, and what does an admin see that I don't?
When Does It Work?
When does the check fire? When does the permission get evaluated? When does the server trust the client, and when does it not? When does the rule boundary matter, and when does the code forget?
Answer those three honestly and you have the full picture. You know who has what privileges. You know how the admin interacts with the regular user. You know where trust sits and where it breaks.
And once the app is that clear in your head, the bugs start showing up as gaps. The places where the developer assumed one thing and the server trusted another. The permission checked on the frontend and forgotten on the backend. Those places don't hide once the app is clear to you.
Confused hunters find nothing. Hunters who understand find everything.
Read the Traffic
Identify the Protocol
First I look at how the app talks to its backend. Is it REST? GraphQL? Something custom, some internal RPC the company rolled themselves?
I open Caido, load the HTTP history, and scroll through the traffic my ten-minute browser session already captured. That alone tells me the shape of everything that comes next.
Figure Out Who the API Serves
Then I check who the API is actually for. Say it's GraphQL. Is this one service for both the regular user and the admin? Or is there a separate admin endpoint sitting somewhere I haven't seen? Is there a partner endpoint that looks the same but trusts different input?
Two identical-looking endpoints with different trust boundaries is exactly where the bugs are.
Walk the Interesting Features First
Then I go to the features, not all of them. I pick the interesting one first. The one that touches other users. The one that shares data. The one that lets me invite, upload, or publish.
Every interesting feature has options, and every option is its own test. Say the platform lets you share a photo. You get three: public, link-only (not browsable anywhere in the app), and password-protected. Three completely different trust models in one feature.
Is the password check client-side or server-side? Are the unlisted links actually unlisted, or is there a listing endpoint somewhere that returns them anyway? Is the public photo really public, or does it leak metadata it shouldn't?
Three options. Three separate investigations.
Capture Anything Interesting
What Counts as Interesting
While I'm doing this, anything interesting I see, I stop and capture it. So let me tell you what counts as interesting: anything that breaks the normal rhythm of the app.
A UI element that flashes on screen and disappears before you can read it. A button that only shows for a split second during a loading state. A request that returns more data than the interface actually displays. A response that comes back faster, or slower, than any other call. A field that renders a value you didn't provide. A header on one request that you never saw on any other. An endpoint that responds differently depending on when you hit it.
These are the anomalies that carry bugs.
Note It, Move On, Come Back
Capture them now, move on, come back later.
I take a screenshot and write a three-word note. Admin present. User ID twice. Client-side permission check. Then I keep going.
That note isn't a to-do list. It's a map.
By the end of the exploration pass I have twenty notes, and every one is a candidate for a real test. Then I test, and the testing isn't random. The notes tell me what to do. The understanding tells me what to try.
The Loop
That's the loop:
- Use the app.
- Read the traffic.
- Count the pieces.
- Walk the features.
- Notice the interesting.
- Test with intent.
When the app is confused, we get bugs. Hold that line.
Stop Only Swapping IDs
The Move Every Hunter Tries First
Classic testing says: change your user ID to someone else's and see if you get their data. It's the first thing every hunter tries, and every developer knows to block it. Usually it fails. Most hunters stop there.
I don't. Because the real bug isn't always in the direct ID swap. It's in what happens when you feed the app a value the developer never expected.
Feed the App a Value It Can't Categorize
Your ID sent as null. Your ID left empty where the code assumes it's always present. The victim's ID dropped into a field that was never meant to hold a user ID at all.
Watch this carefully. If I can't swap my ID for the victim's and read their data, fine. Every developer blocks that. But what if I publish a photo where the publisher field is already the victim's ID? Not my ID swapped with theirs on my own profile. Their ID in a field that was never supposed to accept my input.
Maybe my photo now shows up on their profile. Maybe when someone reports that photo, the victim gets the email. Maybe the permission system now treats them as the owner and me as nobody. Maybe sharing breaks entirely.
That's the creative move. You're not trying to bypass one check. You're trying to feed the app requests it doesn't know how to categorize.
Because confused code doesn't know which rule to apply. It takes the path of least resistance. It trusts the nearest value it can find. Every one of those resolutions is unintended behavior the developer never thought about.
Hunt Confusion, Not IDORs
And look, I'm not telling you to go hunt IDORs specifically. I love broken access control, but that's not the message. The message is that understanding what you're dealing with, without getting confused yourself, is what makes these bugs show themselves.
Stop trying to bypass one check. Start trying to make the app unsure which check to draw.
Build a Library in Your Head
Do this enough times and something shifts. Understanding the app builds a library in your head. Not a payload list. A library of buttons. Three examples.
Permission Panel → Broken Access Control
When I see a permission panel in the interface, I don't open a checklist. The button fires on its own. Who can invite? Who can kick? Who can change roles? What happens if I swap the role value on my own request before it leaves the browser?
URL Field → SSRF
When I see any field that accepts a URL, whether a webhook destination, an image uploaded by link, or a video fetched from a URL, I think SSRF. What does the server do with that URL? Does it follow redirects? Does it accept localhost? What headers does it send? What happens at internal addresses?
Reflected Input → Injection
When I see user-controlled input reflected back into the page, I think injection. Is it in an attribute? A script context? Is it escaped server-side or client-side? Where does this string end up downstream?
Three buttons. Three completely different bug classes. None of them requires a payload list. All of them require understanding the feature well enough to recognize what class of bug lives there.
The more targets you understand, the bigger your library gets. The library is real skill. The toolchain never was.
Read the Code Instead of Believing the App
Nowhere does this matter more than when the app tries to look complicated.
Developers are human. They write obfuscation that looks scary and isn't. They add layers that look complex and aren't. If you don't read the code, you'll believe them. Two patterns that fool automated tools and don't fool anyone who reads.
Pattern One: Base64-Encoded User IDs
You hit an endpoint and the user ID in the request isn't a number. It's a long Base64 string, fifty characters, maybe more. It looks cryptographic. It looks like something you shouldn't touch.
Decode it. It's just your ID wrapped in Base64. That's the whole mystery.
Change the value, re-encode, send. You just swapped to another user. Automated scanners don't catch this, because it isn't a secret. It's the real ID with one layer of encoding. It looks dangerous until you spend three seconds reading it.
Pattern Two: A Signature Hidden in JavaScript
You try to hit an admin endpoint and get a 403. You dig into the failing request and notice it includes a custom header, something like x-admin-signature, and the value is a long hash. If you didn't know the algorithm, you'd assume there's a secret key on the server.
Open the JavaScript file. The app is already loading it in your browser. Search for the header name. There it is, right in the source.
The signature is a SHA-256 hash of three values: your user ID, your user agent, your username. All three you already have. You compute the hash yourself, set the header, and the admin endpoints open up, because the server never actually checks that you're an admin. It only checks that the signature math is valid.
No server-side secret. No key to steal. Just logic the developer pushed into the frontend, hoping nobody would read it. They assumed the signature was proof of admin access. It was only proof you can compute SHA-256.
A scanner will never find that. Scanners look for strings like aws_secret or api_key=. They don't look for broken logic encoded in frontend code. Reading finds it. Scanning doesn't.
What developers think is hard is usually not hard. It's hidden behind one layer of encoding or one function in the source. Read instead of scan, and the whole class of obfuscation becomes trivial.
JavaScript Recon Is Already in Your Proxy
The Files Are Already in Your History
Old recon taught you to collect every JavaScript file the target loads, save them, run scanners, grep for secrets. Most hunters still do this. I stopped.
If I'm hunting on XYZ.com, then XYZ.com calls its own JavaScript files, every one of them. When I browse the app with Caido in the middle, every request to every JavaScript file shows up in my HTTP history already, without me doing anything. No collector, no crawler, no bulk downloader. I use the app, open Caido, and every file the app actually loads is sitting there ready to read.
Follow the Flow Instead of Scraping
But collection was always the easy part. The harder question is what you're even looking for, and why.
Take PII, a classic target for the old-school JS scraper. You run tools that look for email patterns, phone regex, hard-coded credentials in strings, and you hope you get lucky.
Here's what I do instead. I go through the signup flow slowly. I enter my email, my phone, my name, whatever the app asks for, and I watch every request my proxy records. I see exactly where my email goes. I see where my phone number lands. I see which endpoint returns user data to which role under which condition.
Twenty minutes later I know the entire data map: where the PII lives, which endpoints expose it, which role should and shouldn't have access. Any gap in that map is a PII leak I can test directly.
The bulk scraper never finds that. It's looking in random places, hoping. I'm looking at where the data actually moves. Understanding the flow beats scraping the files, every target.
Understanding Beats Scanning
I just spent a whole article on recon: the split, confusing the app, reading JavaScript. And I never mentioned OAuth, authentication flows, or session logic. That's on purpose. OAuth bugs are some of the highest-paying bugs in any program, and every minute there is worth it. But that's a world of its own, and it's not this article.
This is how I do recon in 2026. No subdomain enumeration at the start. No wordlist spam. No JavaScript collectors. Just the app, my proxy, and my head.
When the app is confused, we get bugs. I'd rather run a process that finds one real bug than spend hours building a beautiful spreadsheet that leads nowhere.
If this changes how you start even one target, it did its job.
Now I want to hear from you. If you do it differently, share your actual process, not theory. What do you actually do the moment a new target lands in your lab?
Because the best hunters I know all approach this a little differently, and I learn from every one of them.