iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

DOM-based XSS

DOM-based XSS happens entirely in the browser. Server response is benign; client JS reads attacker-controlled data (location, hash, postMessage) and writes it into the DOM unsafely.

Spot it + fix it

EXAMPLE
// VULNERABLE — reads location.hash and renders it as HTML
const route = location.hash.slice(1);   // e.g. #<img onerror=alert(1)>
document.getElementById('box').innerHTML = '<h1>' + route + '</h1>';

// SAFE — create text nodes / use textContent
const h = document.createElement('h1');
h.textContent = route;
box.replaceChildren(h);

// SAFE — use the Sanitizer API where available
box.innerHTML = '';
box.setHTML(`<h1>${route}</h1>`);   // strips dangerous markup

// Common dangerous sinks to grep for:
//   innerHTML, outerHTML, insertAdjacentHTML, document.write,
//   eval, Function, setTimeout(string, …), setInterval(string, …),
//   href = 'javascript:…',  src = 'javascript:…'
// Common dangerous sources:
//   location.*, document.URL, document.referrer,
//   window.name, postMessage data, fetch JSON without schema-validation

Why it matters

DOM XSS doesn’t touch the server, so server-side filtering doesn’t catch it. CSP + Trusted Types is your safety net — declare which strings can become script.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// VULNERABLE — reads window.location.hash and renders as HTML
const route = location.hash.slice(1);
document.title = route;             // safe (text)
box.innerHTML = '<h1>' + route + '</h1>';   // UNSAFE — XSS
// SAFE
const h = document.createElement('h1');
h.textContent = route;
box.replaceChildren(h);
Try it Yourself »

Discussion

Loading…