Designing an XSS playground that does not lie to the tester
A sandboxed XSS playground is useful only if it makes isolation, parser context, and execution limits explicit.
An XSS playground is easy to build badly.
Create an iframe, write some HTML into it, call it a sandbox. Done. Except now the tester thinks the result means more than it does. The payload executed in your toy environment, not in the target. The parser context is different. The CSP is different. The DOM is different. The sanitizer is missing.
That does not make a playground useless. It means the UI has to be honest.
Isolation first
Payload previews should not run in the same document as the application UI. That sounds obvious until a quick prototype uses dangerouslySetInnerHTML in a preview panel and turns the tool into its own XSS demo.
Use an iframe. Use sandbox flags. Keep the preview state separate from saved collections and application controls.
<iframe sandbox="allow-scripts"></iframe>
Even that choice is a tradeoff. allow-scripts lets JavaScript run inside the frame. Without it, many payloads cannot be demonstrated. With it, you need to ensure the frame does not get same-origin access to the parent. Avoid allow-same-origin unless you have a very specific reason.
Parser context is not portable
Testing this in an empty HTML document:
<img src=x onerror=alert(1)>
does not prove the payload works inside a quoted attribute, a Markdown renderer, a React component, an SVG subtree, or a DOM sink fed by JSON. A playground should be treated as a microscope, not a verdict.
Useful playgrounds let the operator choose wrappers or templates:
<div>PAYLOAD</div>
<input value="PAYLOAD">
<script>const value = "PAYLOAD"</script>
The result still is not the target. But it is closer to the context being tested.
Make failures visible
A blank preview is not enough. Did CSP block it? Did the browser parse it as text? Did an exception fire? Did the payload require a user gesture? Did the event handler attach but never run because the resource loaded successfully?
The console matters. So do small details like whether an img error actually occurs.
<img src=x onerror=alert(1)>
If x accidentally resolves in your environment, the handler may not fire. That has nothing to do with the target.
The playground is not the evidence
For reporting, the playground can help explain the parser behavior. It should not replace target evidence. You still need the vulnerable URL, request, response, DOM path, browser console output, and a remediation note.
The playground is a lab bench. Useful. Controlled. Artificial. Treat it that way.