Endpoint extraction from JS
TL;DR: Bundled frontend JS leaks API routes, role checks, debug flags, and sometimes raw secrets — pull every bundle, run extractors, diff between versions.
What it is
Modern frontends ship minified-but-readable JS that contains every API endpoint the SPA can call, including ones the current user role is not allowed to see. Hidden admin routes, debug endpoints, feature-flagged URLs, even AWS keys and Slack webhooks slip into bundles. Extracting them — and diffing them as the bundle changes — is one of the highest-yield recon techniques on any JS-heavy target.
Preconditions / where it applies
- The application is a SPA (React, Vue, Angular, Svelte, Next.js) — bundle URLs visible in the HTML
- An authenticated session at any role; admin bundles are sometimes only shipped to admin sessions, but most apps ship a single bundle to everyone
- Useful immediately after endpoint-spidering and before fuzzing
Technique
- Collect every JS URL the app loads. Combine the spider output (endpoint-spidering) with passive sources (
gau,waybackurls) and the running app’s network panel:1
katana -u https://app.target.tld -jc -silent | grep -E '\.js(\?|$)' | sort -u > js.txt
- Mirror locally and beautify before grepping — minified one-liners hide patterns:
1 2
while read u; do wget -q "$u" -O "$(echo $u | sha1sum | cut -c1-12).js"; done < js.txt js-beautify -r *.js
- Run extractors. They overlap in coverage; using two is usually enough:
linkfinder.py -i 'app.*.js' -o cli— original regex-based URL extractorxnLinkFinder -i js/ -sf target.tld -o links.txt— newer, smarter, scope-awarejsluice urls --include-source app.js— Go-based, also extracts secretstrufflehog filesystem js/— credentials, tokens
- Sort, dedupe, scope-filter, then feed back into nuclei, ffuf, or manual triage. Pay special attention to:
*/internal/*,*/admin/*,*/debug/*,*/v1beta/*paths- Feature flag names — sometimes the flag itself is the bug (
isInternalUser,bypassMfa) - Role strings (
"role":"ADMIN") hinting at mass-assignment opportunities
- Hash each bundle and store. On every recon loop (continuous-recon-automation) diff against the previous hash; a changed bundle means re-extract — new routes ship in the diff.
Detection and defence
- Defenders should split admin and tenant bundles, strip dead code in the build, and never embed credentials in frontend code
- Source-map suppression in production is a partial mitigation; aggressive minification slows extractors but does not stop them
- For the hunter: hitting newly-extracted admin endpoints triggers WAF 403/401 patterns the defender can correlate — pace yourself
References
- GerbenJavado/LinkFinder — original JS link extractor
- xnl-h4ck3r/xnLinkFinder — scope-aware modern successor
- BishopFox/jsluice — Go-based URL + secret extractor with AST