Modern web apps ship a lot of their logic to the browser. That means JavaScript files often contain API paths, internal hostnames, feature flags and sometimes keys that were never meant to be public. JavaScript recon is the process of collecting these files, reading them, and pulling out anything that helps you understand the target better. In this post I’ll show a simple workflow you can repeat on every in-scope target: collect JS files, keep the live ones, extract endpoints, flag possible secrets, and then review the interesting parts by hand.
Why JavaScript recon is worth your time
When you browse an app, you only see the pages the developers want you to see. The JavaScript bundle often knows about much more. It may reference routes for admin panels, old API versions, beta features or internal services. None of this is a bug on its own, but it gives you a much larger list of things to understand and test. If you are new to the wider picture, my post on recon and its importance in bug bounty hunting explains where this step fits.
Here is what I usually look for inside JS files:
- Endpoints and API routes such as
/api/v2/users/exportor/internal/report. - Hostnames and subdomains that did not show up during subdomain enumeration.
- Parameter names the app accepts but does not advertise.
- Comments and TODOs that hint at unfinished or risky features.
- Possible secrets like tokens or keys that were committed by mistake.
Step 1: Collect the JavaScript files
First you need a list of JS files the target loads. There are two good sources: files the live site loads right now, and files that appeared in the past. For current files, a crawler like katana works well because it renders pages and follows links.
echo https://target.example | katana -jc -d 3 -o katana.txt
grep -iE '\.js(\?|$)' katana.txt | sort -u > js-live.txtFor historical files, pull archived URLs with gau or waybackurls. Old JS files sometimes point to endpoints that still work even after the UI stopped using them.
echo target.example | gau | grep -iE '\.js(\?|$)' | sort -u > js-old.txt
cat js-live.txt js-old.txt | sort -u > js-all.txtStep 2: Keep only the files that still load
Your combined list will have dead links, duplicates and files that return errors. Run it through httpx to keep the ones that respond, and note their size so you can spot the big bundles.
cat js-all.txt | httpx -mc 200 -content-length -o js-reachable.txtLarge files are usually the main application bundles, and those are the ones most worth reading. Small files are often third-party libraries you can skip.
JavaScript recon: extracting endpoints and paths
Reading a minified bundle by hand is painful. Tools help you pull the interesting strings out first. LinkFinder is built for this. It scans a JS file and lists the paths and endpoints it finds using a set of regular expressions.
python3 linkfinder.py -i https://target.example/static/app.js -o cliTo process a whole list of files, loop over them and save the results into one place:
while read url; do
python3 linkfinder.py -i "$url" -o cli
done < js-reachable.txt | sort -u > endpoints.txtNow you have a list of candidate paths. Many will be fragments or partial routes. Build full URLs from the useful ones and check which actually respond:
cat endpoints.txt | httpx -mc 200,201,301,302,401,403 -o endpoints-live.txtPay attention to 401 and 403 responses. A path that exists but blocks you is often more interesting than a plain 404, because it confirms the route is real.
Looking for secrets the safe way
Sometimes developers leave tokens or keys in front-end code by mistake. SecretFinder is a companion to LinkFinder that scans JS for patterns that look like API keys, tokens and similar strings.
python3 SecretFinder.py -i https://target.example/static/app.js -o cliBe careful here, and be honest with yourself about what you find. Not every match is a real secret. Many front-end keys, such as public analytics or maps keys, are meant to be public and restricted by domain. Before you report anything, confirm two things:
- The key actually grants access to something sensitive.
- The asset it touches is in scope for the program.
Never use a key you find to pull real user data or run up charges on someone’s account. Prove the issue with the smallest possible test, then report it. If a key clearly belongs to a third-party service outside the program’s scope, note it in your report but do not test against that service.
Reading the file by hand
Tools miss things, so the last step is always your own eyes. Once you have a short list of the biggest and most relevant bundles, open them and search for a few key terms:
fetch(andaxiosto find where the app makes requests./api,/admin,/internalto find sensitive route prefixes.role,isAdmin,debugto find client-side checks worth testing on the server.
Client-side checks are a classic source of findings. If the JavaScript hides an admin button unless isAdmin is true, the real question is whether the server also enforces that rule. Sometimes it does not. Prettify the file first (most browsers do this with a single click in the Sources tab) so the minified code becomes readable.
Common mistakes
- Only checking live files. Archived JS from
gauoften reveals endpoints the current site removed from the UI but left running on the server. - Trusting every secret match. SecretFinder flags patterns, not confirmed keys. Verify before you report, and never test a key against out-of-scope services.
- Ignoring small apps. Even a single bundle on a small target can expose the whole API surface. My guide to recon on small, medium and large scope targets covers how to scale this.
- Hammering endpoints. When you test the paths you found, respect the program’s rate limits. A slow, careful scan keeps you out of trouble.
Tips to make this repeatable
Save your output in one folder per target, with clear file names like js-all.txt, endpoints-live.txt and secrets.txt. The next time the target ships a new release, rerun the same steps and diff the results. New bundles mean new endpoints, and being early is an advantage.
If you want to automate more of your recon, have a look at Bug Bounty Automation: The Tools Behind Faster Recon.
Conclusion
JavaScript recon turns the code the browser already downloads into a map of the target. Collect the files, keep the live ones, pull out endpoints and possible secrets, then read the important bundles yourself. Stay inside scope, verify before you report, and treat any key you find with care. If you want to go deeper and practise this with me, join a session on my live online classes on bug bounty and recon.
