Why should you rely on framework protections against XSS?
Because XSS payloads exploit dozens of obscure parsing quirks (case tricks, Unicode escapes, comment breakouts) that hand-rolled filters miss — framework escaping is battle-tested against all of them.
A hand-rolled filter can only block the tricks its author thought of. The trouble is that a payload
need not look anything like <script>alert(1)</script> — it can be assembled out of parsing quirks,
and a single line can stack eleven of them at once:
-->'"/></sCript><deTailS open x=">" ontoggle=(co\u006efirm)``>
Read left to right, every fragment defeats a different assumption:
| Fragment | What it defeats |
|---|---|
--> |
escapes an HTML comment context — a filter that assumed the input stays commented out |
' then " |
breaks out of a single-quoted attribute, then a double-quoted one, covering both without knowing which is in use |
/> |
closes whatever tag is still open |
</sCript> |
escapes a JavaScript context, in mixed case so a blocklist matching the literal </script> misses it |
<deTailS …> |
a less well-known tag (<details>) that a blocklist of script / img / iframe never enumerated |
open |
makes the element render already expanded, so the handler fires with no user interaction |
x=">" |
a dummy attribute whose value mimics a tag close, to derail a naive parser |
ontoggle= |
a less well-known event handler — again, not on anyone's list |
co\u006efirm |
the function name confirm written with a Unicode escape, so searching for the literal text fails |
(…) around the name |
parentheses wrapped around the function name, so the literal string confirm( a denylist searches for never appears |
`` |
backticks invoke the function instead of () — a tagged template call, so a filter looking for a call's parentheses sees none |
The lesson is a counting argument, not a matter of taste. There are well over a hundred tags, dozens of event handlers, several nested parsing contexts and multiple encodings for the same character — a denylist has to be right every single time, an attacker only once. Framework escaping wins because it works the other way round: it encodes whatever the data is for the context it lands in, so a novel tag or a brand-new handler needs no new rule. Use it, and never switch it off for untrusted data.
Go deeper:
OWASP XSS Filter Evasion Cheat Sheet — the catalogue of bypasses a hand-rolled filter has to beat.