Why another xss cheat sheet still matter
Modern frameworks ≠ XSS-free. Auto-escaping in React/Angular/Svelte reduces templating holes, but real systems still ship DOM API misuse, unsafe 3rd-party widgets, permissive Markdown/WYSIWYG, جافا سكريبت: URL handlers, SVG/MathML, JSONP remnants, and implicit trust in location/hash/postMessage.
Vector ecosystems evolve. PortSwigger continuously annotates payloads by event / tag / attribute / browser, drastically reducing “tribal memory.” That curation is gold when you need wide coverage without reinventing payload taxonomies.
Filtering alone is not a defense. OWASP has repeated this for over a decade: correctness depends on the data’s rendering context. Combining proper output encoding, sanitization (for user-authored HTML), policy (CSP, Trusted Types), and framework hygiene is non-negotiable.

Attack-surface × context matrix
Use this matrix as your execution checklist when scripting Playwright/Burp/Nuclei validations or code audits. Each row ties a rendering context to risky sinks, common entries, the first defensive moveو how to verify at scale.
| السياق | Risky sinks (illustrative) | Typical entry points | Primary defense | How to validate at scale |
|---|---|---|---|---|
| نص HTML | داخليHTML, template string concatenation | reflected params, search boxes, user bios, comments | HTML output encoding; never push untrusted HTML | Headless render + DOM-taint hooks; diff DOM before/after |
| Attribute | href/src/action, any on* handler | جافا سكريبت: URLs, SVG attributes, البيانات: URLs | Attribute/URL encoding; prohibit جافا سكريبت:; CSP | Attribute-wise fuzz; monitor auto-triggers and navigation |
| جافا سكريبت | التقييم, Function, setTimeout(string) | JSONP callbacks, dynamic script concat/parsing | Ban dynamic evaluation; serialize inputs; sandbox if needed | Hook eval/Function; collect call stacks & arguments |
| URL/Nav | location, document.URL concat | open redirects, hash/fragment injections | Canonicalize; strict allowlists; never stitch raw strings | Real-UA replay; redirect-chain tracing |
| Templating/SSR | unsafe filters/partials | server-side template data crossings | Strict template escaping; variable whitelists | Template unit tests + placeholder fuzzing |
| Rich content | WYSIWYG/Markdown/SVG/MathML | pasted external HTML/SVG; user profile content | Allowlist sanitization (DOMPurify); CSP; drop dangerous tags | Batch payload replay + CSP violation logging |
Minimal reproducible examples (MREs) you can actually run
1) Attribute context + zero-interaction trigger
<input autofocus onfocus="fetch('/beacon?xss=1')">
Why it matters: Focus events self-trigger on load in many UX flows (search fields, quick prompts). Replace with <svg onload=…> أو <img onerror="…"> to test different trigger semantics.
2) SVG carrier + URL handling quirks
<svg><a xlink:href="javascript:fetch('/beacon?svg')">x</a></svg>
Why it matters: SVG is a separate XML namespace with historically quirky attribute parsing. Teams often forget to sanitize SVG or allow it through Markdown renderers.
3) DOM-based XSS (source → sink lineage)
<script>
const q = new URL(location).hash.slice(1);
document.getElementById('out').innerHTML = q; // sink
</script>
<div id="out"></div>
Why it matters: The classic “read from URL, write to DOM” anti-pattern. It’s everywhere in legacy sites and internal tools. Fix with context-correct encoding and never write directly to HTML sinks.
Defensive baseline (engineering-first, not slogans)
- Output encoding by context. Encode for HTML / Attribute / URL / JS respectively. Framework auto-escaping does not cover hand-rolled DOM updates.
- Allowlist sanitization for user HTML. When business logic requires rich content (comments, bios, knowledge bases), use DOMPurify (or equivalent) with hardened configs; avoid blacklist “word-chopping.”
- Content Security Policy. Start with
script-src 'self'+ block inline by default; setobject-src 'none'وbase-uri 'none'. Adopt Trusted Types in Chromium to force safe DOM APIs at compile/runtime. - Dangerous API audit. Ban or gate
eval/new Function/setTimeout(string)and dynamic JSON→code conversions. Enforce with ESLint rules during build and fail CI when violations surface. - Test & verify as code. Automate payload replay. Pair with CSP violation reporting و gateway/log correlation to separate “demoable popups” from exploitable paths that matter to the business.
From cheat sheet to pipeline: automation that ships
The shortest path from “vector library” to “production-grade assurance” is a five-stage loop:
- Context discovery. Static scans (ESLint rules, semantic grep) + runtime probes that tag potential sinks (
داخليHTML, attribute setters, navigation points). - Vector scheduling. Map each sink/context to a curated pool of payloads (attribute events, tag quirks, URL handlers), filtering by browser and feature flags.
- Headless proofing. Playwright/Chromium runs per vector. Capture console, network, CSP violations, and DOM mutations.
- Signal correlation. Join headless findings with API gateway و app logs to bin “noise vs. real.” This kills false positives on day one.
- Evidence-first reporting. Auto-attach screenshots, HTTP traces, DOM before/after diffs, and policy violations—then score confidence so engineers know where to start.
Minimal Playwright replayer (drop-in snippet)
import { chromium } from 'playwright';
const vectors = [
'#\"><img src="x" onerror="fetch(\">',
'#<svg onload="fetch(\">'
];
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
page.on('console', m => console.log('console:', m.text()));
page.on('pageerror', e => console.error('pageerror:', e));
for (const v of vectors) {
await page.goto('https://target.example/' + v);
await page.screenshot({ path: `evidence_${encodeURIComponent(v)}.png` });
}
await browser.close();
})();
Productionize it: add source→sink lineage labels to each run, turn on CSP report-only to collect violations, and store DOM diffs to make regressions obvious in PRs.
Framework realities you should design for
- React/JSX. Auto-escaping helps, but dangerouslySetInnerHTML and raw
ref.current.innerHTML = …re-open the sink. Treat them as code smells; gate behind a sanitizer and a Trusted Types policy. - Angular. The sanitizer is decent, but bypassSecurityTrustHtml and similar APIs can punch holes; document every bypass and restrict to vetted sources.
- Next/Nuxt/SSR. Server-generated pages must echo only encoded content. Never rely on client frameworks to “clean up” server mistakes.
- Markdown/MDX/WYSIWYG. Treat them as HTML ingestion problems. Harden your renderer, sandbox untrusted widgets, and purge event attributes/URL handlers.
- SVG/MathML. If you must allow them, cap the feature set and run a sanitizer that understands XML namespaces. If not critical, convert to safe raster on the server.
Practical payload families you’ll actually need
- On-event autotrigger:
autofocus,onload,على خطأ,onanimationstart,onfocus,onpointerenter. Great for proving exploitability without user clicks. - URL handlers:
جافا سكريبت:,البيانات:, and occasionallyvbscript:(legacy). Enforce allowlists. - Template collisions: Split/concat tricks that slip through naive filters (e.g., breaking out of attribute contexts then re-entering HTML).
- DOM clobbering: Overwrite IDs/names to redirect code paths and land a sink.
- Mutation-observer timing: Triggers that exploit dynamic updates instead of initial load.
CSP and Trusted Types: from “nice to have” to guardrail
- CSP gives you a policy language to constrain script sources and inline execution. Start strict, then widen only for vetted cases. Pair with
report-uri/report-toand harvest violation reports in your telemetry. - Trusted Types force developers to pass policy-created values into DOM APIs that would otherwise accept raw strings (
داخليHTML,outerHTML,insertAdjacentHTML,Range#createContextualFragment). This removes whole classes of DOM XSS by construction. - Rollout tip: run CSP in
report-onlyfor two sprints; fix violations; then enforce. Introduce a single app-wide Trusted Types policy and only issue “blessed” HTML via vetted builders.
How to prove exploitability to engineers
- Repro scripts: Provide a one-liner (URL or curl) and a Playwright branch to replay.
- DOM diff: Show the exact node that changed and the path (
#app > .profile > .bio). - Call stacks: For JS sinks, include stack traces from your
eval/Functionhooks. - CSP evidence: Attach violation JSON for inline/script src breaches.
- Business narrative: “This can exfiltrate session tokens from
/accountvia an injected<img>beacon” beats “alert popped” every time.
Running this xss cheat sheet inside Penligent
If you’re already using بنليجنت as an automated pentest platform, you can package the above into a single runnable template:
- Task template: “XSS Recon + Validate.” The agent performs reconnaissance (subdomain/port/fingerprint), schedules vectors per detected context, executes headless replay, and correlates signals with logs/gateways to cut noise.
- Evidence-first export. Findings ship with confidence scores, reproducible steps, screenshots, CSP violation logs, and DOM diffs your engineers can trust.
- Where it helps most. Big scopes with mixed legacy + SPA stacks, or teams migrating to CSP/Trusted Types and needing proof-driven triage rather than payload trivia.

Common pitfalls that keep biting seasoned teams
- Sanitizing the input, not the output. If you must accept HTML, sanitize و still encode on output based on the destination context; the two are not interchangeable.
- Allowing
جافا سكريبت:for “flexibility.” Kill it entirely; whitelist only specific protocols (https,mailto, maybetel). - Treating Markdown as “safe text.” It’s a renderer—its plugins decide safety. Audit allowed tags/attributes; consider server-side rasterization for untrusted SVG.
- Ignoring non-HTML contexts. URL concatenation and JSON→JS evals are repeat offenders. Strengthen the “no-string-to-code” policy.
- Trusting one environment. XSS that fails in headless may still succeed on mobile Chromium or older desktop builds. Keep a browser matrix for high-value apps.
Production checklist , pin this next to your CI badge
- Context-aware encoding utilities with unit tests for HTML/Attr/URL/JS
- DOMPurify (or equivalent) locked to a hardened config for rich-content paths
- CSP مع
script-src 'self'(no unsafe-inline),object-src 'none',base-uri 'none'; violation collection wired to telemetry - Trusted Types policy + build-time lint rules to block raw string sinks
- ESLint rules banning
eval/new Function/setTimeout(string)(CI-enforced) - Playwright replay suite seeded with PortSwigger-style vectors; per-vector screenshots + DOM diffs
- Automated signal correlation with app logs / API gateway events
- Evidence-first reports with confidence scores and business-impact notes
- PR template lines: “Introduces new HTML sinks?” “Bypasses sanitizer?” “TT policy updated?”
- Regular review of third-party widgets/WYSIWYG/Markdown settings
الأسئلة الشائعة
Q: If we already use React/Angular, do we still need this?
A: Yes. Frameworks don’t police all DOM writes, third-party widgets, or Markdown/SVG. You still need sanitizer + CSP + TT, and you must avoid writing untrusted data into raw DOM sinks.
Q: Should we block all inline scripts with CSP?
A: Yes, by default. Use nonces or hashes only when absolutely necessary and document the exception. The long-term goal is to avoid inline scripts altogether.
Q: Is sanitization enough?
A: No. Sanitization reduces attack surface for HTML ingestion, but you still need correct output encoding and policy guardrails. Different problems, different tools.
Q: Which browsers do we test?
A: At minimum, your user base’s top two desktop + mobile engines. Keep a small matrix; some vectors are browser-specific or feature-flag gated.
Further reading (authoritative)
- PortSwigger — Cross-Site Scripting (XSS) Cheat Sheet — a living catalog of vectors, PoCs, and browser notes.
- OWASP — XSS Prevention Cheat Sheet — rigorous, context-specific encoding strategies and do/don’t tables.
- OWASP — DOM-based XSS Prevention Cheat Sheet — source→sink patterns and mitigations in the browser.
- PortSwigger — What is XSS? — structured tutorial and hands-on labs for training new hires.
Appendix: quick sanitation & encoding reference
- HTML text nodes → escape
& < > " ' / - Attribute values → HTML-attribute encode + disallow event attributes from untrusted data
- URLs → encode components; allowlist protocols; never write raw
جافا سكريبت:/البيانات: - JS strings → serialize safely; never pass user data into code-interpreting APIs
Closing note: A useful xss cheat sheet is one you can wire into your pipeline—not a poster of clever payloads. Start with context discovery, schedule vectors by context, replay headlessly, correlate with logs, and ship evidence with confidence scores. Whether you adopt Penligent or roll your own harness, drive the process with evidence and let policy enforce the guardrails.

