Quick answer
The client-side JS of any modern SPA hides internal endpoints, API keys, authorization logic and undocumented routes. The methodology: collect all the .js with getJS → extract endpoints with LinkFinder → detect secrets with trufflehog → look for .map files (source maps in production are a common fail) → reconstruct the full source. Typical bounty for a secret exposed in JS: €500-€3000.
Static analysis
Gather JS files
cat alive.txt | getJS -complete | sort -u > js_urls.txt
# Download all JS files
cat js_urls.txt | while read url; do
wget -q "$url" -P ./js_files/
done
# Bonus: Wayback Machine — old versions with deprecated endpoints
waybackurls target.com | grep "\.js$" | sort -u >> js_urls.txt
Identify endpoints with LinkFinder
python3 LinkFinder.py -i https://target.com/main.js -o cli
# Batch mode
cat js_urls.txt | while read url; do
python3 LinkFinder.py -i "$url" -o cli
done 2>/dev/null | sort -u > endpoints.txt
LinkFinder uses regex to detect strings with a URL shape in the code. It often reveals internal endpoints /api/admin/*, /internal/* that never appear in the docs.
Detect secrets with TruffleHog
trufflehog filesystem ./js_files/ --only-verified
cat js_urls.txt | while read url; do
curl -s "$url" | trufflehog --regex --entropy=False
done
--only-verified avoids false positives: trufflehog makes a request to the real API (GitHub, AWS) to confirm the key is still active.
Manual grep patterns
Sometimes faster than the tools:
| Pattern | What it finds |
|---|---|
| `grep -rEi "(api[_-]?key | api[_-]?secret |
grep -rEi "AKIA[0-9A-Z]{16}" | AWS access keys |
grep -rEi "firebaseio\.com" | Public Firebase databases |
| `grep -rEi "(password | passwd |
grep -rEohi "https?://[a-zA-Z0-9./?=_-]*" | Full URLs |
Source maps — the favorite fail
When a production build includes .map files, the original (un-minified) source code is accessible. Vercel, Netlify and many CI/CD pipelines upload them by default unless the dev explicitly excludes them.
# Check if the map exists
curl -s -o /dev/null -w "%{http_code}" https://target.com/main.js.map
Reconstruct the source
npx source-map-explorer main.js main.js.map
# Or in Chrome DevTools: Sources tab → if the .map loads, you see the original src/ directories
[!warning] Impact Source maps reveal: folder structure, internal file names, author comments, feature flag logic, undocumented admin endpoints. Medium-high severity.
Dynamic analysis
Function monitoring
Inject into the browser console to intercept any fetch or XMLHttpRequest call:
const originalFetch = window.fetch;
window.fetch = function() {
console.log('Fetch called:', arguments);
return originalFetch.apply(this, arguments);
};
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
console.log('XHR called:', arguments);
return originalOpen.apply(this, arguments);
};
Useful for mapping which endpoints each UI action invokes without touching Burp.
Strategic breakpoints
In DevTools → Sources tab:
- XHR/Fetch breakpoints: pause when a specific URL pattern is invoked.
- Event listener breakpoints:
submit,click— useful for auth flows. - DOM breakpoints: subtree modifications on sensitive elements (e.g. a password
<input>). - Conditional breakpoints: only pause if a variable has a certain value.
React Native — Android bundles
React Native apps ship the JS as index.android.bundle packaged in the .apk. It usually contains staging endpoints, Firebase configs and hardcoded API keys.
# Extract bundle
unzip app.apk -d extracted/
find extracted/ -name "index.android.bundle"
# Source map check
grep -rnis 'sourceMappingURL' index.android.bundle
# If a .map is referenced → it may be in production → full source
# Look for secrets
grep -rnis 'apiKey\|FIREBASE_API_KEY\|FIREBASE_AUTH_DOMAIN\|secret\|token\|password' \
index.android.bundle
Frida — dynamic instrumentation
To hook Java or native methods at runtime without recompiling the app.
Android setup
adb push frida-server-*-android-x86_64 /data/local/tmp/frida-server
adb shell chmod +x /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &
Java method override
Java.perform(function () {
var MainActivity = Java.use("com.example.app.MainActivity");
MainActivity.check.implementation = function (input) {
return true; // Bypass validation
};
});
SSL pinning bypass
frida -U -f com.example.app -l ssl-pinning-bypass.js
Lets you intercept the app's HTTPS traffic in Burp/mitmproxy.
Hunting checklist
-
getJS -completeon every alive host - Wayback machine for historical .js
- LinkFinder on each .js → internal endpoints
- trufflehog with
--only-verifiedfor active secrets - Manual grep for AWS/Firebase/API key patterns
- Check for
.mapfiles in production → if present, full source - React Native: extract
index.android.bundle, grep secrets - DevTools Sources: XHR breakpoints in critical flows
- Frida if the app is mobile and you want to bypass client-side logic
Related labs
Practice client-side JS analysis and secret hunting in bundles with Recon and JavaScript Analysis labs.
Practice this in a lab
Client Side Js Recon
Keep learning · free account
Save your progress, unlock advanced payloads and rank your flags.
There's an extra payload at the end
The trick to reconstruct the full source code when a SPA exposes its .map file in production — and why top-10 companies still leak source maps in 2026.
€7.99/mo · cancel anytime
Related articles
Prototype Pollution — from malicious JSON to XSS, RCE and auth bypass
How an attacker pollutes Object.prototype and breaks the code's assumptions. Client-side and server-side vectors, gadgets in lodash/jQuery/Angular.
Client-side admin bypass — boolean manipulation + BAC in a modern SPA
Real Quora report: SPA with an isAdmin boolean in localStorage that controls the UI + a backend that doesn't validate server-side. How to chain a boolean flip with BAC for admin takeover.
Basic recon methodology — from the domain to the vulnerable endpoints
The minimal recon pipeline for bug bounty: subdomain enum, live host discovery, URL collection, parameter discovery. Free tools and execution order.