Special welcome gift. Get 10% off your first purchase with code “WELCOME10”. Find out more!10% off your first order: WELCOME10

Cover image: JavaScript Recon: Finding Hidden Endpoints and Secrets in JS Files

JavaScript Recon: Finding Hidden Endpoints and Secrets in JS Files

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/export or /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.txt

For 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.txt

Step 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.txt

Large 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 cli

To 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.txt

Now 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.txt

Pay 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 cli

Be 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:

  1. The key actually grants access to something sensitive.
  2. 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( and axios to find where the app makes requests.
  • /api, /admin, /internal to find sensitive route prefixes.
  • role, isAdmin, debug to 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 gau often 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.

You May Also Like

Use search operators to find subdomains, documents, admin pages and API docs for your in-scope target, without sending a single...
A practical walkthrough of passive and active subdomain enumeration, from subfinder and crt.sh to puredns, dnsx and httpx.
Bug bounty hunting has become a popular way for security professionals to test and improve their skills, all while helping...