DOM-based XSS Vulnerability Demonstration
Client-side XSS through document.write injection
# (hash/fragment) from the URL and writes it directly to the page using
document.write() without sanitization. The payload never touches the server —
it's purely client-side.(none)
document.write(userInput)#<img src=x onerror=alert(1)>#<svg onload=alert(document.doindex)>Working Payloads:
#<img src=x onerror=alert('XSS')> — Image error event#<svg onload=alert(1)> — SVG onload#<body onload=alert(document.cookie)> — Body onload#<input onfocus=alert(1) autofocus> — Input autofocus
Why it works: The app reads window.location.hash and passes it
directly to document.write(). The browser executes any HTML/JS injected in the fragment.
// VULNERABLE: Reads fragment and writes to DOM unsafely
function displayFragment() {
const fragment = window.location.hash.substring(1);
const decoded = decodeURIComponent(fragment);
if (decoded) {
// DANGER: document.write with user input!
document.getElementById('output').innerHTML = decoded;
// OR: document.write(decoded);
}
}
// FIX 1: Use textContent instead of innerHTML
document.getElementById('output').textContent = decoded;
// FIX 2: Escape HTML before inserting
function escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
document.getElementById('output').innerHTML = escapeHtml(decoded);
// FIX 3: Avoid document.write entirely
// Never use document.write() with user input!