🔐Encoding & Escaping

XSS Attack Prevention

Prevent Cross-Site Scripting (XSS) attacks with proper escaping and sanitization

Explanation

XSS prevention requires context-aware escaping, Content Security Policy, and sanitizing user-generated HTML.

Examples

Vulnerable code
Input
innerHTML = userInput
Output
⚠️ XSS risk!
Safe approach
Input
textContent = userInput
Output
✓ No HTML parsing

Code Examples

JavaScript
// ❌ VULNERABLE - innerHTML with user input
element.innerHTML = userInput; // XSS risk!

// ✅ SAFE - textContent (no HTML parsing)
element.textContent = userInput;

// ✅ SAFE - React (auto-escapes by default)
function Component({ userInput }) {
  return <div>{userInput}</div>; // Escaped automatically
}

// ❌ VULNERABLE - React dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userInput }} />

// ✅ SAFE - Sanitize HTML with DOMPurify
import DOMPurify from 'dompurify';

const cleanHtml = DOMPurify.sanitize(userInput);
element.innerHTML = cleanHtml;

// ✅ SAFE - Vue (auto-escapes by default)
<template>
  <div>{{ userInput }}</div> <!-- Escaped -->
  <div v-text="userInput"></div> <!-- Escaped -->
  <div v-html="sanitizedHtml"></div> <!-- Use with DOMPurify -->
</template>

// Context-aware escaping
function escapeHtml(str) {
  return str.replace(/[&<>"']/g, m => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  })[m]);
}

function escapeAttribute(str) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

function escapeJs(str) {
  return str
    .replace(/\\/g, '\\\\')
    .replace(/"/g, '\\"')
    .replace(/'/g, "\\'")
    .replace(/\n/g, '\\n')
    .replace(/\r/g, '\\r')
    .replace(/</g, '\\u003c')
    .replace(/>/g, '\\u003e');
}

// URL context
function escapeUrl(url) {
  // Only allow http/https protocols
  if (!url.match(/^https?:\/\//)) {
    return '';
  }
  return encodeURI(url);
}

// Content Security Policy (CSP) headers
// Set in server config or meta tag
const cspHeader = "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'";

// ✅ Safe data attribute approach
element.dataset.userInput = userInput;
const safe = element.dataset.userInput;
Python
import html
from markupsafe import escape, Markup

# ❌ VULNERABLE - Direct string interpolation in templates
template = f"<div>{user_input}</div>"  # XSS risk!

# ✅ SAFE - Jinja2 auto-escaping
from jinja2 import Template
template = Template('<div>{{ user_input }}</div>')
safe_html = template.render(user_input=user_input)

# ✅ SAFE - Django templates (auto-escape by default)
# In template: {{ user_input }}

# ✅ SAFE - Manual escaping
escaped = html.escape(user_input)

# ✅ SAFE - Sanitize HTML with bleach
import bleach

allowed_tags = ['p', 'br', 'strong', 'em', 'a']
allowed_attrs = {'a': ['href', 'title']}

clean_html = bleach.clean(
    user_input,
    tags=allowed_tags,
    attributes=allowed_attrs,
    strip=True
)

# Context-specific escaping
def escape_js(text):
    return (text
        .replace('\\', '\\\\')
        .replace('"', '\\"')
        .replace("'", "\\'")
        .replace('\n', '\\n')
        .replace('\r', '\\r')
        .replace('<', '\\u003c')
        .replace('>', '\\u003e'))

💡 Tips

  • Use framework auto-escaping (React, Vue, Angular)
  • textContent is safer than innerHTML
  • Sanitize HTML with DOMPurify or bleach
  • Implement Content Security Policy (CSP)
  • Validate input on both client and server
  • Escape for context (HTML, attribute, JS, CSS, URL)
  • Use httpOnly cookies for session tokens
  • Never trust user input
  • Disable inline scripts with CSP

⚠️ Common Pitfalls

  • innerHTML with user input = XSS
  • eval() with user input = code execution
  • href="javascript:..." = XSS
  • onclick= attributes with user input = XSS
  • Wrong context escaping (HTML in JS context)
  • Incomplete sanitization leaves vulnerabilities
  • Double encoding can bypass filters
  • DOM-based XSS in client-side code