Skip to content

XSS Cheat Sheet

XSS payloads by context — HTML, attribute, JS string, URL, DOM — with filter evasion, polyglots and CSP checks.

How it works

Cross-site scripting is an output-encoding failure: attacker-controlled text reaches a browser context — HTML body, attribute, JavaScript string, URL, or a DOM sink — without the encoding that context requires. The payload that fires depends entirely on where the input lands, which is why random spraying fails and context analysis wins. This reference organizes probes by context so you test the one that matches the sink.

The core contexts are covered with minimal probes: body markup (<svg onload>, <img onerror>), attribute breakouts for single and double quotes, JavaScript string escapes including the </script> block closer, URL-scheme sinks, and DOM-delivered probes through fragments and query parameters. A polyglot section handles the common case where you do not yet know the context.

Filter evasion entries document why blacklists fail: case variation, slash-for-whitespace, HTML entities, Unicode escapes and template-literal calls without parentheses. These are not party tricks — they are the regression suite your sanitizer and CSP must survive.

Authorized testing only. Fire these against systems you own or have written permission to assess. The defense section covers context-aware encoding, sanitization with vetted libraries, and a Content Security Policy that assumes the first payload will eventually land.

Worked example

Identify the sink first: your search term is reflected inside a double-quoted attribute, value="TERM". Body payloads cannot fire here; an attribute breakout can.

ProbeResult after injectionSignal
<svg onload=alert(1)>Encoded as text inside the attributeNo execution — wrong context.
" onmouseover=alert(1) x="Attribute closed, handler addedFires on hover — attribute context confirmed.
' autofocus onfocus=alert(1) x='Same breakout, single-quotedUse when the attribute is single-quoted.
  1. Find the reflection: Locate where input reappears and identify the exact context.
  2. Pick the context probe: Use the minimal payload for that context, or a polyglot when unsure.
  3. Escalate only to evasion: If blocked, work through case, entity, slash and template-literal variants.
  4. Fix and replay: Apply context encoding plus CSP, then re-fire every probe until all are inert.

The fix is context-correct encoding: attribute values get attribute encoding (&quot; for quotes), body content gets HTML encoding, JS strings get JS escaping plus quoting. After patching, replay the same probe and expect inert text.

Common errors and edge cases

  • Encoding for the wrong context. HTML-encoding a value placed in a JavaScript string still executes. Each context needs its own encoder; there is no universal escape.
  • innerHTML sinks. Client-side rendering with innerHTML, document.write or jQuery .html() creates DOM XSS even when the server encodes correctly. Use textContent or a sanitizer.
  • Blacklists always leak. Filtering the literal string <script> leaves case variants, slashes, entities and template literals. Sanitize by structure, not by keyword.
  • javascript: URLs. Href and form-action sinks need scheme allowlists (http, https, mailto); encoding alone does not stop a javascript: URL.
  • CSP as last line. A strict script-src without 'unsafe-inline' neutralizes most reflected payloads even when encoding misses one — but CSP does not fix the underlying bug.

Code equivalents

These are the defensive patterns each probe is meant to verify: context-correct encoding and a sanitizer for rich text.

ContextSafe pattern
Server (HTML body)html.escape(user_input) in Python, htmlspecialchars($in, ENT_QUOTES) in PHP — quotes included for attributes.
JavaScript (DOM)el.textContent = userInput — never innerHTML with untrusted data; sanitize with DOMPurify when markup is required.
CSP headerscript-src 'self'; object-src 'none'; base-uri 'self' — inline handlers stop executing, even injected ones.

Frequently asked questions

Which payload should I try first?

Identify the reflection context, then use that section's minimal probe: svg-onload for body, a quote breakout for attributes, ';alert(1)// for JS strings, javascript: for URL sinks. If the context is unknown, start with the polyglot.

Is testing with alert(1) enough as proof?

For reflection yes — it proves script execution in the victim's context. For impact assessment on your own app, document.domain via confirm(1) is cleaner evidence, and that is as far as you need to go.

Why did my payload show up encoded but the page still broke?

Partial encoding: the server encoded < and > but not the quote terminating the attribute. Context-correct means every meta-character of that context is handled.

Does a strict CSP make XSS impossible?

No — it makes exploitation much harder by blocking inline script and external sources, but DOM sinks with allowed scripts, JSONP, and script gadgets can remain. CSP is the safety net, not the fix.

Are these payloads legal to use?

Only on systems you own or have explicit written permission to test. Unauthorized injection is illegal in most jurisdictions regardless of how small the probe is.

Privacy note

All processing happens in your browser. The values you enter never leave your device and are never transmitted to ToolPlex.