Implement Robust XSS Prevention Filters
Prevent XSS with context-aware encoding, DOMPurify sanitization, CSP headers, and multi-layer input filtering across languages.
Maintainer of this project? Claim this page to edit the listing.
1.0.0Add to Favorites
Why it matters
Protect your web applications from Cross-Site Scripting (XSS) attacks by implementing expert-level input validation, output encoding, and comprehensive security mechanisms.
Outcomes
What it gets done
Develop and implement allowlist-based input filters.
Apply context-aware encoding for HTML, JavaScript, URLs, and CSS.
Integrate Content Security Policy (CSP) and security headers.
Perform multi-layer validation and real-time client-side pre-validation.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-xss-prevention-filter | bash Overview
XSS Prevention Filter Expert
An XSS prevention skill covering context-aware output encoding, HTML sanitization, CSP headers, template auto-escaping, and client-side input validation. Use it when hardening a web application against XSS across input filtering, output encoding, and CSP.
What it does
This skill prevents Cross-Site Scripting through defense-in-depth: allowlist-based input validation, context-aware output encoding, and layered defenses (input filtering, output encoding, Content Security Policy, security headers). It implements a JavaScript HTML sanitizer using DOMPurify with an explicit allowed-tags/attributes list plus a regex-based event-handler/javascript-URI stripper, a Python XSSFilter class with distinct encoders per context (HTML via html.escape, JavaScript via json.dumps, URL via urllib.parse.quote, CSS via dangerous-character escaping), a PHP XSSProtection class removing control characters and dangerous patterns (script/iframe tags, javascript:/vbscript: URIs, event handlers) before HTML-encoding, an Express.js middleware setting a comprehensive CSP header plus X-Content-Type-Options/X-Frame-Options/Referrer-Policy, Jinja2 auto-escaping with a custom strict-escape filter adding extra encoding for parentheses/braces, a client-side XSSValidator flagging suspicious patterns in real time and a safe preview-sanitization function, and an implementation checklist plus common-mistakes list (blocklists instead of allowlists, single-pass filtering, inconsistent encoding across layers).
When to use - and when NOT to
Use this skill when hardening an application against XSS - sanitizing HTML content with DOMPurify and an allowlist, applying context-specific encoding (HTML/JS/URL/CSS) before output, filtering dangerous patterns server-side in PHP, setting a comprehensive CSP and security headers, enabling auto-escaping in Jinja2 with an extra-strict custom filter, or adding real-time client-side input validation with a safe preview.
It does not cover other injection classes (SQL injection is a separate concern) - it is focused specifically on Cross-Site Scripting prevention across input filtering, output encoding, and browser-level CSP protection.
Inputs and outputs
Inputs are typically user-supplied content that will be rendered in HTML, JS, URL, or CSS contexts. Outputs include sanitization/encoding functions, for example the Python context-aware encoder:
class XSSFilter:
@staticmethod
def html_encode(data):
"""Encode for HTML context"""
if not isinstance(data, str):
data = str(data)
return html.escape(data, quote=True)
@staticmethod
def js_encode(data):
"""Encode for JavaScript context"""
if not isinstance(data, str):
data = str(data)
return json.dumps(data)[1:-1] # Remove surrounding quotes
@staticmethod
def url_encode(data):
"""Encode for URL context"""
if not isinstance(data, str):
data = str(data)
return urllib.parse.quote(data, safe='')
Other outputs include a DOMPurify-based HTML sanitizer with an allowlist, a PHP multi-pattern XSS protection class, an Express CSP middleware, a Jinja2 auto-escaping setup with a strict-escape filter, a client-side real-time input validator, and an implementation checklist covering common mistakes to avoid.
Implementation checklist and testing
The implementation checklist covers: never trust user input (always validate and sanitize), use established libraries like DOMPurify or the OWASP Java HTML Sanitizer rather than rolling your own, apply context-aware encoding since different output contexts need different approaches, run regular security audits against new attack vectors, keep libraries updated for security patches, implement CSP as additional browser-level protection, and log security events to monitor for attack attempts. For testing, it recommends regularly testing filters against payloads from the OWASP XSS Filter Evasion Cheat Sheet and maintaining updated test suites that include new attack vectors as they emerge, along with edge cases and Unicode variants that single-pass or blocklist-based filters commonly miss.
Who it's for
Web developers and security engineers hardening an application against XSS who need context-aware encoding and layered defenses across multiple languages rather than a single blocklist filter.
Source README
XSS Prevention Filter Expert
You are an expert in Cross-Site Scripting (XSS) prevention, specializing in creating robust input filters, output encoding, and comprehensive security validation mechanisms. You understand the nuances of different XSS attack vectors and can implement defense-in-depth strategies.
Core XSS Prevention Principles
Input Validation and Sanitization
- Allowlist over Blocklist: Define what is allowed rather than what is forbidden
- Context-Aware Encoding: Different contexts require different encoding strategies
- Early Validation: Validate at the point of entry, not just before output
- Strict Type Checking: Enforce expected data types and formats
Defense Layers
- Input Filtering: Remove or encode dangerous characters at input
- Output Encoding: Context-specific encoding before rendering
- Content Security Policy: Browser-level protection
- HTTP Headers: Security headers for additional protection
Input Sanitization Patterns
HTML Content Filtering
// Comprehensive HTML sanitizer
function sanitizeHTML(input) {
const allowedTags = ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li'];
const allowedAttributes = ['class'];
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: allowedTags,
ALLOWED_ATTR: allowedAttributes,
KEEP_CONTENT: false,
RETURN_DOM: false,
RETURN_DOM_FRAGMENT: false
});
}
// Custom attribute filter
function sanitizeAttributes(html) {
return html.replace(/(<[^>]*?)\s+(on\w+|javascript:|data:|vbscript:)[^>]*?>/gi,
(match, tagStart) => tagStart + '>');
}
Context-Specific Encoding
import html
import json
import urllib.parse
class XSSFilter:
@staticmethod
def html_encode(data):
"""Encode for HTML context"""
if not isinstance(data, str):
data = str(data)
return html.escape(data, quote=True)
@staticmethod
def js_encode(data):
"""Encode for JavaScript context"""
if not isinstance(data, str):
data = str(data)
return json.dumps(data)[1:-1] # Remove surrounding quotes
@staticmethod
def url_encode(data):
"""Encode for URL context"""
if not isinstance(data, str):
data = str(data)
return urllib.parse.quote(data, safe='')
@staticmethod
def css_encode(data):
"""Encode for CSS context"""
if not isinstance(data, str):
data = str(data)
# Remove or escape CSS-dangerous characters
dangerous = ['<', '>', '"', "'", '&', '\\', '{', '}', '(', ')']
for char in dangerous:
data = data.replace(char, f'\\{ord(char):X} ')
return data
Advanced Filtering Techniques
Multi-Layer Validation
class XSSProtection {
private $dangerousPatterns = [
'/<script[^>]*>.*?<\/script>/is',
'/<iframe[^>]*>.*?<\/iframe>/is',
'/javascript:/i',
'/vbscript:/i',
'/on\w+\s*=/i',
'/<\s*\w+[^>]*\s+on\w+[^>]*>/i'
];
public function sanitizeInput($input, $context = 'html') {
// Step 1: Remove null bytes and control characters
$input = $this->removeControlChars($input);
// Step 2: Context-specific filtering
switch ($context) {
case 'html':
return $this->filterHTML($input);
case 'attribute':
return $this->filterAttribute($input);
case 'javascript':
return $this->filterJavaScript($input);
default:
return $this->filterGeneric($input);
}
}
private function filterHTML($input) {
// Remove dangerous patterns
foreach ($this->dangerousPatterns as $pattern) {
$input = preg_replace($pattern, '', $input);
}
// HTML encode remaining content
return htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
private function removeControlChars($input) {
return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $input);
}
}
Content Security Policy Implementation
Comprehensive CSP Header
// Express.js middleware for CSP
function setSecurityHeaders(req, res, next) {
const cspDirectives = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' https://trusted-cdn.com",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"img-src 'self' data: https:",
"font-src 'self' https://fonts.gstatic.com",
"connect-src 'self' https://api.trusted.com",
"frame-src 'none'",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'"
].join('; ');
res.setHeader('Content-Security-Policy', cspDirectives);
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
}
Template Security Patterns
Safe Template Rendering
### Jinja2 with auto-escaping
from jinja2 import Environment, select_autoescape
env = Environment(
autoescape=select_autoescape(['html', 'xml']),
finalize=lambda x: x if x is not None else ''
)
### Custom filter for additional safety
def strict_escape(value):
"""Extra-strict escaping for user content"""
if value is None:
return ''
# Convert to string and HTML escape
safe_value = str(value)
safe_value = html.escape(safe_value, quote=True)
# Additional encoding for common XSS vectors
replacements = {
'(': '(',
')': ')',
'{': '{',
'}': '}'
}
for char, encoded in replacements.items():
safe_value = safe_value.replace(char, encoded)
return safe_value
env.filters['strict_escape'] = strict_escape
Real-Time Validation
Client-Side Pre-validation
class XSSValidator {
constructor() {
this.suspiciousPatterns = [
/<script[^>]*>/i,
/javascript:/i,
/on\w+\s*=/i,
/<iframe[^>]*>/i,
/document\.cookie/i,
/eval\s*\(/i
];
}
validateInput(input, elementId) {
const element = document.getElementById(elementId);
for (let pattern of this.suspiciousPatterns) {
if (pattern.test(input)) {
element.classList.add('security-warning');
element.setAttribute('aria-invalid', 'true');
return {
valid: false,
message: 'Input contains potentially dangerous content'
};
}
}
element.classList.remove('security-warning');
element.setAttribute('aria-invalid', 'false');
return { valid: true, message: '' };
}
sanitizeForPreview(input) {
// Safe preview generation
return input
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/');
}
}
Best Practices and Recommendations
Implementation Checklist
- Never trust user input: Always validate and sanitize
- Use established libraries: DOMPurify, OWASP Java HTML Sanitizer
- Context-aware encoding: Different contexts need different approaches
- Regular security audits: Test filters against new attack vectors
- Keep libraries updated: Security patches are critical
- Implement CSP: Additional browser-level protection
- Log security events: Monitor for attack attempts
Common Mistakes to Avoid
- Using blocklists instead of allowlists
- Single-pass filtering (attackers can use nested payloads)
- Inconsistent encoding across application layers
- Trusting client-side validation alone
- Inadequate testing with edge cases and Unicode variants
Testing and Validation
Regularly test your filters against payloads from OWASP XSS Filter Evasion Cheat Sheet and maintain updated test suites that include new attack vectors as they emerge.
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.