๐งช Interactive Security Demonstrations with Code
HTML Injection Prevention
๐ Understanding the Vulnerability
HTML injection occurs when untrusted data is inserted into the DOM without proper sanitization. The browser interprets this data as code, executing any embedded scripts.
๐ก๏ธ Trusted Types Defense Mechanisms:
- โข TrustedHTML Type: Only accepts sanitized HTML through policies
- โข Default Policy: Fallback sanitization for legacy code
- โข CSP Integration: Blocks violations via require-trusted-types-for
- โข Sink Protection: Guards innerHTML, outerHTML, insertAdjacentHTML, and more
๐ Learn More: MDN Trusted Types Documentation | Web.dev Guide
๐ป Implementation Code
// 1. Create a sanitization policy for HTML content
const htmlSanitizationPolicy = trustedTypes.createPolicy('html-sanitizer', {
  createHTML: (dirty) => {
    // Remove dangerous elements and attributes
    const cleaned = dirty
      // Remove script tags
      .replace(/
โข ">
                    
                    
                    
                    
                        Sanitized Output:
                        
                    
                Dynamic Script Security
๐ Script Injection Vectors
                        Attackers exploit dynamic script creation to execute arbitrary code. Common targets include 
                        eval(), Function(), 
                        setTimeout/setInterval with strings, and dynamic script elements.
                    
๐ก๏ธ TrustedScript & TrustedScriptURL:
- โข TrustedScript: For inline script content and eval-like functions
- โข TrustedScriptURL: For external script sources and worker URLs
- โข Policy Validation: Scripts must pass through createScript/createScriptURL
- โข Import Maps: Protection extends to ES6 module imports
๐ป Implementation Code
// Create policies for script content and URLs
const scriptPolicy = trustedTypes.createPolicy('script-loader', {
  createScript: (script) => {
    // Validate script content
    if (script.includes('eval') || script.includes('Function(')) {
      throw new Error('Dangerous functions not allowed');
    }
    return script;
  },
  
  createScriptURL: (url) => {
    // Whitelist trusted domains
    const trustedDomains = [
      'https://cdn.jsdelivr.net',
      'https://unpkg.com',
      'https://cdnjs.cloudflare.com',
      window.location.origin
    ];
    
    const urlObj = new URL(url, window.location.origin);
    
    if (!trustedDomains.some(domain => urlObj.href.startsWith(domain))) {
      throw new Error(`Untrusted script source: ${url}`);
    }
    
    return url;
  }
});// Safe dynamic script loading
function loadScriptSafely(scriptUrl) {
  const script = document.createElement('script');
  
  // Use the policy to validate the URL
  script.src = scriptPolicy.createScriptURL(scriptUrl);
  
  script.onerror = () => {
    console.error('Script failed to load:', scriptUrl);
  };
  
  script.onload = () => {
    console.log('Script loaded successfully:', scriptUrl);
  };
  
  document.head.appendChild(script);
}
// Safe inline script execution
function executeInlineScript(code) {
  const script = document.createElement('script');
  
  // Use the policy to validate the script content
  script.textContent = scriptPolicy.createScript(code);
  
  document.body.appendChild(script);
  document.body.removeChild(script); // Clean up
}
// Example usage
loadScriptSafely('https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js');
executeInlineScript('console.log("Safe script execution");');// โ UNSAFE - Using eval (blocked by Trusted Types)
function unsafeEval(userCode) {
  eval(userCode); // Throws TypeError with Trusted Types
}
// โ UNSAFE - Using Function constructor
function unsafeFunction(userCode) {
  new Function(userCode)(); // Also blocked
}
// โ UNSAFE - setTimeout with string
function unsafeTimeout(userCode) {
  setTimeout(userCode, 0); // Blocked
}
// โ
 SAFE - Use JSON.parse for data
function safeJSONParse(jsonString) {
  try {
    const data = JSON.parse(jsonString);
    return data;
  } catch (e) {
    console.error('Invalid JSON:', e);
  }
}
// โ
 SAFE - Use Function references
function safeTimeout(callback) {
  setTimeout(callback, 0); // Pass function, not string
}
// โ
 SAFE - Use Web Workers for isolation
function safeWorker(code) {
  const blob = new Blob([code], { type: 'application/javascript' });
  const worker = new Worker(URL.createObjectURL(blob));
  return worker;
}Script Execution Log:
Event Handler Safety
๐ Event Handler Attack Surface
                        Inline event handlers are a major XSS vector. Attributes like onclick, 
                        onload, onerror, and 
                        over 70 other event handlers can execute JavaScript directly from HTML.
                    
๐ก๏ธ Safe Event Handling Patterns:
- โข addEventListener: Programmatic event binding (preferred)
- โข Event Delegation: Single listener for multiple elements
- โข Data Attributes: Store data separately from handlers
- โข CSP unsafe-inline: Block all inline handlers when possible
๐ป Implementation Code
// โ
 SAFE: Using addEventListener
function createSafeButton(text, message) {
  const button = document.createElement('button');
  button.textContent = text;
  button.className = 'btn btn-primary';
  
  // Safe event handler attachment
  button.addEventListener('click', function(event) {
    // Access data from closure or data attributes
    console.log('Button clicked:', message);
    alert(message);
  });
  
  return button;
}
// โ
 SAFE: Multiple event listeners
function attachMultipleHandlers(element) {
  element.addEventListener('mouseenter', () => {
    element.classList.add('hover');
  });
  
  element.addEventListener('mouseleave', () => {
    element.classList.remove('hover');
  });
  
  element.addEventListener('click', (e) => {
    e.preventDefault();
    handleClick(element);
  });
}
// โ UNSAFE: Never use inline handlers
// element.innerHTML = ``;
// โ
 SAFE: Create elements programmatically
const container = document.getElementById('buttonContainer');
const safeBtn = createSafeButton('Click Me', 'Hello, World!');
container.appendChild(safeBtn);// Event Delegation Pattern - Single listener for multiple elements
class ButtonManager {
  constructor(container) {
    this.container = container;
    this.buttons = new Map();
    
    // Single event listener for all buttons
    this.container.addEventListener('click', this.handleClick.bind(this));
  }
  
  handleClick(event) {
    // Check if clicked element is a button
    const button = event.target.closest('[data-action]');
    if (!button) return;
    
    const action = button.dataset.action;
    const id = button.dataset.id;
    
    // Execute appropriate handler
    switch(action) {
      case 'delete':
        this.handleDelete(id);
        break;
      case 'edit':
        this.handleEdit(id);
        break;
      case 'view':
        this.handleView(id);
        break;
    }
  }
  
  addButton(id, action, text) {
    const button = document.createElement('button');
    button.textContent = text;
    button.dataset.action = action;
    button.dataset.id = id;
    button.className = 'delegated-btn';
    
    this.container.appendChild(button);
    this.buttons.set(id, button);
  }
  
  handleDelete(id) {
    console.log('Deleting:', id);
    const button = this.buttons.get(id);
    if (button) {
      button.remove();
      this.buttons.delete(id);
    }
  }
  
  handleEdit(id) {
    console.log('Editing:', id);
  }
  
  handleView(id) {
    console.log('Viewing:', id);
  }
}
// Usage
const manager = new ButtonManager(document.getElementById('container'));
manager.addButton('1', 'delete', 'Delete Item 1');
manager.addButton('2', 'edit', 'Edit Item 2');
manager.addButton('3', 'view', 'View Item 3');// Using data attributes to store information safely
function createInteractiveElement(config) {
  const element = document.createElement('div');
  element.className = 'interactive-card';
  
  // Store data in data attributes (automatically escaped)
  element.dataset.userId = config.userId;
  element.dataset.action = config.action;
  element.dataset.metadata = JSON.stringify(config.metadata);
  
  // Safe HTML content
  element.innerHTML = `
    ${escapeHtml(config.title)}
    ${escapeHtml(config.description)}
    
  `;
  
  // Attach event handler that reads from data attributes
  const button = element.querySelector('.action-btn');
  button.addEventListener('click', function() {
    const userId = element.dataset.userId;
    const action = element.dataset.action;
    const metadata = JSON.parse(element.dataset.metadata);
    
    performAction(userId, action, metadata);
  });
  
  return element;
}
// HTML escaping function
function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}
// Action handler
function performAction(userId, action, metadata) {
  console.log('Performing action:', {
    userId,
    action,
    metadata
  });
  
  // Send to server or handle locally
  fetch('/api/action', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userId, action, metadata })
  });
}
// Usage
const card = createInteractiveElement({
  userId: '123',
  action: 'update',
  title: 'User Profile',
  description: 'Click to update profile',
  metadata: { timestamp: Date.now(), source: 'web' }
});
document.getElementById('container').appendChild(card);Safely Created Buttons:
URL Injection Protection
๐ Dangerous URL Schemes
                        URLs can execute code through various schemes: javascript:, 
                        data:, vbscript: (IE), 
                        and even jar: protocols can be exploited.
                    
๐ก๏ธ URL Validation Strategies:
- โข Protocol Whitelist: Only allow http://, https://, mailto:
- โข URL Constructor: Parse and validate URL structure
- โข Same-Origin Checks: Restrict to same domain when needed
- โข Sanitize Parameters: Clean query strings and fragments
๐ป Implementation Code
// Comprehensive URL validation
class URLValidator {
  constructor() {
    // Allowed protocols
    this.allowedProtocols = ['http:', 'https:', 'mailto:'];
    
    // Blocked patterns
    this.blockedPatterns = [
      /javascript:/i,
      /data:(?!image\/)/i,  // Allow data: URLs only for images
      /vbscript:/i,
      /file:/i,
      /jar:/i
    ];
  }
  
  validate(url) {
    // Check for blocked patterns first
    for (const pattern of this.blockedPatterns) {
      if (pattern.test(url)) {
        throw new Error(`Blocked URL pattern: ${url}`);
      }
    }
    
    try {
      // Use URL constructor for parsing
      const urlObj = new URL(url, window.location.origin);
      
      // Check protocol
      if (!this.allowedProtocols.includes(urlObj.protocol)) {
        throw new Error(`Invalid protocol: ${urlObj.protocol}`);
      }
      
      // Additional checks
      this.checkForOpenRedirect(urlObj);
      this.checkForIDN(urlObj);
      
      return urlObj.href;
    } catch (e) {
      console.error('URL validation failed:', e);
      return null;
    }
  }
  
  checkForOpenRedirect(urlObj) {
    // Check for common open redirect patterns
    const params = urlObj.searchParams;
    const redirectParams = ['url', 'redirect', 'return', 'next', 'goto'];
    
    for (const param of redirectParams) {
      const value = params.get(param);
      if (value && !this.isSameOrigin(value)) {
        console.warn('Potential open redirect:', value);
      }
    }
  }
  
  checkForIDN(urlObj) {
    // Check for IDN homograph attacks
    if (urlObj.hostname.includes('xn--')) {
      console.warn('IDN domain detected:', urlObj.hostname);
    }
  }
  
  isSameOrigin(url) {
    try {
      const urlObj = new URL(url, window.location.origin);
      return urlObj.origin === window.location.origin;
    } catch {
      return false;
    }
  }
}
// Usage
const validator = new URLValidator();
const safeUrl = validator.validate(userProvidedUrl);// URL Sanitization for different contexts
class URLSanitizer {
  // For anchor tags
  sanitizeForHref(url) {
    // Remove javascript: and data: protocols
    if (/^(javascript|data|vbscript):/i.test(url)) {
      return '#blocked';
    }
    
    try {
      const urlObj = new URL(url, window.location.origin);
      
      // For external links, add rel="noopener noreferrer"
      if (urlObj.origin !== window.location.origin) {
        return {
          href: urlObj.href,
          rel: 'noopener noreferrer',
          target: '_blank'
        };
      }
      
      return { href: urlObj.href };
    } catch {
      return { href: '#invalid' };
    }
  }
  
  // For image sources
  sanitizeForImg(url) {
    // Allow data URLs for images
    if (/^data:image\//i.test(url)) {
      return url;
    }
    
    // Block other data URLs
    if (/^data:/i.test(url)) {
      return '/placeholder.png';
    }
    
    // Validate other URLs
    try {
      const urlObj = new URL(url, window.location.origin);
      if (urlObj.protocol === 'https:' || urlObj.protocol === 'http:') {
        return urlObj.href;
      }
    } catch {
      return '/placeholder.png';
    }
    
    return '/placeholder.png';
  }
  
  // For iframe sources
  sanitizeForIframe(url) {
    // Very strict - only allow same-origin or trusted domains
    const trustedDomains = [
      'https://www.youtube.com',
      'https://player.vimeo.com'
    ];
    
    try {
      const urlObj = new URL(url);
      
      // Check if same-origin
      if (urlObj.origin === window.location.origin) {
        return url;
      }
      
      // Check trusted domains
      if (trustedDomains.some(domain => url.startsWith(domain))) {
        return url;
      }
    } catch {
      return 'about:blank';
    }
    
    return 'about:blank';
  }
}
// Usage
const sanitizer = new URLSanitizer();
// Create safe link
function createSafeLink(url, text) {
  const a = document.createElement('a');
  const sanitized = sanitizer.sanitizeForHref(url);
  
  if (typeof sanitized === 'object') {
    Object.assign(a, sanitized);
  } else {
    a.href = sanitized;
  }
  
  a.textContent = text;
  return a;
}// Safe navigation and redirection
class SafeNavigator {
  // Safe window.location assignment
  navigateTo(url) {
    const validated = this.validateURL(url);
    if (validated) {
      window.location.href = validated;
    } else {
      console.error('Invalid navigation URL:', url);
      this.handleInvalidNavigation();
    }
  }
  
  // Safe window.open
  openWindow(url, target = '_blank') {
    const validated = this.validateURL(url);
    if (validated) {
      const newWindow = window.open(validated, target, 'noopener,noreferrer');
      return newWindow;
    }
    return null;
  }
  
  // Safe form action
  setFormAction(form, url) {
    const validated = this.validateURL(url);
    if (validated) {
      form.action = validated;
      // Add CSRF token if needed
      this.addCSRFToken(form);
    }
  }
  
  // Validate and sanitize URL
  validateURL(url) {
    try {
      const urlObj = new URL(url, window.location.origin);
      
      // Block dangerous protocols
      if (!['http:', 'https:'].includes(urlObj.protocol)) {
        return null;
      }
      
      // For production: implement additional checks
      // - Domain whitelist
      // - Path validation
      // - Parameter sanitization
      
      return urlObj.href;
    } catch {
      return null;
    }
  }
  
  // Handle invalid navigation attempts
  handleInvalidNavigation() {
    // Log security event
    console.error('Blocked navigation attempt');
    
    // Show user-friendly error
    alert('The link you clicked appears to be invalid.');
    
    // Optionally report to server
    this.reportSecurityEvent('invalid_navigation');
  }
  
  // Add CSRF protection
  addCSRFToken(form) {
    const token = document.querySelector('meta[name="csrf-token"]')?.content;
    if (token) {
      const input = document.createElement('input');
      input.type = 'hidden';
      input.name = 'csrf_token';
      input.value = token;
      form.appendChild(input);
    }
  }
  
  // Report security events
  reportSecurityEvent(event) {
    fetch('/api/security/report', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        event,
        timestamp: Date.now(),
        url: window.location.href
      })
    });
  }
}
// Usage
const navigator = new SafeNavigator();
// Safe navigation
document.getElementById('safeLink').addEventListener('click', (e) => {
  e.preventDefault();
  navigator.navigateTo(e.target.href);
});
// Safe form submission
const form = document.getElementById('myForm');
navigator.setFormAction(form, '/api/submit');Validated Links:
๐ Security Console
Real-time security events and policy violations:
๐ฆ Polyfilling Trusted Types
๐ฏ Quick Start
Trusted Types is natively supported in Chromium 83+ and Safari 15.4+. For other browsers, use the official polyfill:
<!-- Add before your application code -->
<script src="https://cdn.jsdelivr.net/npm/trusted-types@latest/dist/es5/trustedtypes.api_only.build.js"
        integrity="sha384-XqVn80KjGxKBXv4lAWYmf2L3DGfqFRGPwr8HQxvLzXpQPL5j5UTc5hyLT8vfVZGg"
        crossorigin="anonymous"></script>๐ฅ Installation Methods
# Install the polyfill
npm install trusted-types
# For TypeScript projects, also install type definitions
npm install --save-dev @types/trusted-types
# Or using Yarn
yarn add trusted-types
yarn add -D @types/trusted-types<!-- API-only version (recommended for most apps) -->
<script src="https://cdn.jsdelivr.net/npm/trusted-types@latest/dist/es5/trustedtypes.api_only.build.js"></script>
<!-- Or from unpkg -->
<script src="https://unpkg.com/trusted-types@latest/dist/es5/trustedtypes.api_only.build.js"></script>
<!-- Full version with enforcement (requires CSP configuration) -->
<script src="https://cdn.jsdelivr.net/npm/trusted-types@latest/dist/es5/trustedtypes.build.js"
        data-csp="require-trusted-types-for 'script'"></script>// Ultra-lightweight fallback (1 line!)
// Add this before any code that uses Trusted Types
if(typeof trustedTypes == 'undefined') {
  window.trustedTypes = {
    createPolicy: (name, rules) => rules
  };
}
// This provides basic compatibility but NO enforcement
// Policies will return plain strings instead of TrustedType objectsโ๏ธ React Integration with TypeScript
// types/trusted-types.d.ts
declare global {
  interface Window {
    trustedTypes?: TrustedTypePolicyFactory;
  }
}
// utils/trustedTypes.ts
import DOMPurify from 'dompurify';
export interface SecurityPolicy {
  createHTML(input: string): TrustedHTML | string;
  createScript(input: string): TrustedScript | string;
  createScriptURL(input: string): TrustedScriptURL | string;
}
export const createTrustedTypesPolicy = (name: string = 'react-app'): TrustedTypePolicy | null => {
  if (typeof window !== 'undefined' && window.trustedTypes) {
    return window.trustedTypes.createPolicy(name, {
      createHTML: (input: string) => DOMPurify.sanitize(input),
      createScript: (input: string) => input,
      createScriptURL: (url: string) => {
        const allowedDomains = [
          'https://cdn.jsdelivr.net',
          'https://unpkg.com',
          window.location.origin
        ];
        
        const urlObj = new URL(url, window.location.origin);
        if (allowedDomains.some(domain => urlObj.href.startsWith(domain))) {
          return url;
        }
        throw new Error(`Untrusted URL: ${url}`);
      }
    });
  }
  return null;
};
// polyfills/index.ts
import 'trusted-types';
// Initialize default policy for React
if (typeof window !== 'undefined') {
  const policy = createTrustedTypesPolicy('default');
  
  // Feature detection
  if (!window.trustedTypes) {
    console.warn('Trusted Types not natively supported, using polyfill');
  }
}// components/SafeHTML.tsx
import React, { useEffect, useRef, memo } from 'react';
import DOMPurify from 'dompurify';
interface SafeHTMLProps {
  content: string;
  className?: string;
  tagName?: keyof JSX.IntrinsicElements;
}
const SafeHTML = memo(({ 
  content, 
  className, 
  tagName = 'div' 
}) => {
  const containerRef = useRef(null);
  const policyRef = useRef(null);
  useEffect(() => {
    // Create policy once on mount
    if (window.trustedTypes && !policyRef.current) {
      try {
        policyRef.current = window.trustedTypes.createPolicy('safe-html', {
          createHTML: (input: string) => DOMPurify.sanitize(input, {
            ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br', 'ul', 'li', 'ol'],
            ALLOWED_ATTR: ['href', 'target', 'rel']
          })
        });
      } catch (e) {
        console.warn('Failed to create Trusted Types policy:', e);
      }
    }
  }, []);
  useEffect(() => {
    if (!containerRef.current) return;
    try {
      if (policyRef.current) {
        // Use Trusted Types policy
        const trustedHTML = policyRef.current.createHTML(content);
        containerRef.current.innerHTML = trustedHTML as string;
      } else {
        // Fallback for browsers without Trusted Types
        containerRef.current.innerHTML = DOMPurify.sanitize(content);
      }
    } catch (error) {
      console.error('Failed to set HTML content:', error);
      containerRef.current.textContent = content; // Safe fallback
    }
  }, [content]);
  const Tag = tagName as any;
  return    // hooks/useTrustedTypes.ts
import { useMemo, useCallback, useRef, useEffect, useState } from 'react';
import DOMPurify from 'dompurify';
interface UseTrustedTypesOptions {
  policyName?: string;
  allowedTags?: string[];
  allowedAttributes?: string[];
}
export const useTrustedHTML = (
  dirty: string,
  options: UseTrustedTypesOptions = {}
): { __html: string } => {
  const { 
    policyName = 'react-html',
    allowedTags,
    allowedAttributes 
  } = options;
  return useMemo(() => {
    const sanitizeOptions = {
      ALLOWED_TAGS: allowedTags,
      ALLOWED_ATTR: allowedAttributes
    };
    if (window.trustedTypes) {
      try {
        const policy = window.trustedTypes.createPolicy(policyName, {
          createHTML: (input: string) => DOMPurify.sanitize(input, sanitizeOptions)
        });
        return { __html: policy.createHTML(dirty) as string };
      } catch (e) {
        console.warn('Trusted Types policy creation failed:', e);
      }
    }
    
    // Fallback to DOMPurify without Trusted Types
    return { __html: DOMPurify.sanitize(dirty, sanitizeOptions) };
  }, [dirty, policyName, allowedTags, allowedAttributes]);
};
// Hook for managing script URLs
export const useTrustedScriptURL = (url: string): string | null => {
  const [trustedURL, setTrustedURL] = useState(null);
  
  useEffect(() => {
    if (window.trustedTypes) {
      try {
        const policy = window.trustedTypes.createPolicy('script-loader', {
          createScriptURL: (input: string) => {
            const allowedOrigins = [
              'https://cdn.jsdelivr.net',
              'https://unpkg.com',
              window.location.origin
            ];
            
            const urlObj = new URL(input, window.location.origin);
            if (allowedOrigins.some(origin => urlObj.href.startsWith(origin))) {
              return input;
            }
            throw new Error(`Untrusted script URL: ${input}`);
          }
        });
        
        const trusted = policy.createScriptURL(url);
        setTrustedURL(trusted as string);
      } catch (e) {
        console.error('Failed to create trusted script URL:', e);
        setTrustedURL(null);
      }
    } else {
      // No Trusted Types support, return original URL
      setTrustedURL(url);
    }
  }, [url]);
  
  return trustedURL;
};
// Usage in component:
const MyComponent: React.FC<{ htmlContent: string }> = ({ htmlContent }) => {
  const trustedContent = useTrustedHTML(htmlContent, {
    allowedTags: ['p', 'a', 'strong', 'em'],
    allowedAttributes: ['href', 'target']
  });
  
  return ;
}; // pages/_document.tsx (Next.js)
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
  return (
    
      
        {/* Content Security Policy with Trusted Types */}
        
        
        {/* Load polyfill before any other scripts */}
        
      
      
        
        ๐ TypeScript Configuration
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "esnext",
    "moduleResolution": "node",
    "types": ["trusted-types", "dompurify"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react-jsx"
  },
  "include": ["src/**/*", "types/**/*"],
  "exclude": ["node_modules"]
}// types/security.ts
export interface TrustedTypesPolicy {
  name: string;
  createHTML: (input: string) => TrustedHTML | string;
  createScript: (input: string) => TrustedScript | string;
  createScriptURL: (input: string) => TrustedScriptURL | string;
}
export type PolicyName = 'default' | 'react-app' | 'sanitizer' | 'script-loader';
export interface PolicyConfig {
  name: T;
  rules: Partial<{
    createHTML: (input: string) => string;
    createScript: (input: string) => string;
    createScriptURL: (input: string) => string;
  }>;
}
// Generic policy factory
export class PolicyFactory {
  private static policies = new Map();
  static create(config: PolicyConfig): TrustedTypePolicy | null {
    if (!window.trustedTypes) return null;
    const existing = this.policies.get(config.name);
    if (existing) return existing;
    try {
      const policy = window.trustedTypes.createPolicy(config.name, config.rules);
      this.policies.set(config.name, policy);
      return policy;
    } catch (error) {
      console.error(`Failed to create policy ${config.name}:`, error);
      return null;
    }
  }
  static get(name: PolicyName): TrustedTypePolicy | undefined {
    return this.policies.get(name);
  }
}
// Utility types for safer API usage
export type SafeHTML = TrustedHTML | string;
export type SafeScript = TrustedScript | string;
export type SafeScriptURL = TrustedScriptURL | string;
// React-specific types
export interface SafeInnerHTML {
  __html: SafeHTML;
}
export interface TrustedTypesContext {
  policy: TrustedTypePolicy | null;
  isSupported: boolean;
  createTrustedHTML: (input: string) => SafeHTML;
  createTrustedScript: (input: string) => SafeScript;
  createTrustedScriptURL: (input: string) => SafeScriptURL;
}    // utils/typeGuards.ts
// Type guards for Trusted Types
export const isTrustedHTML = (value: unknown): value is TrustedHTML => {
  return typeof value === 'object' && value !== null && 
         value.constructor.name === 'TrustedHTML';
};
export const isTrustedScript = (value: unknown): value is TrustedScript => {
  return typeof value === 'object' && value !== null && 
         value.constructor.name === 'TrustedScript';
};
export const isTrustedScriptURL = (value: unknown): value is TrustedScriptURL => {
  return typeof value === 'object' && value !== null && 
         value.constructor.name === 'TrustedScriptURL';
};
export const hasTrustedTypesSupport = (): boolean => {
  return typeof window !== 'undefined' && 
         'trustedTypes' in window && 
         window.trustedTypes !== undefined;
};
// Safe conversion functions with type narrowing
export const toSafeHTML = (value: string | TrustedHTML): string => {
  if (isTrustedHTML(value)) {
    return value.toString();
  }
  return value;
};
// Validation helper
export const validateTrustedType = (
  value: T | string,
  expectedType: 'html' | 'script' | 'scriptURL'
): void => {
  if (!hasTrustedTypesSupport()) return;
  const validators = {
    html: isTrustedHTML,
    script: isTrustedScript,
    scriptURL: isTrustedScriptURL
  };
  const isValid = validators[expectedType](value) || typeof value === 'string';
  
  if (!isValid) {
    throw new TypeError(
      `Expected ${expectedType} to be TrustedType or string, got ${typeof value}`
    );
  }
};
// React component prop validation
export const validateHTMLProp = (
  props: { dangerouslySetInnerHTML?: { __html: unknown } }
): void => {
  if (props.dangerouslySetInnerHTML) {
    const html = props.dangerouslySetInnerHTML.__html;
    if (hasTrustedTypesSupport() && !isTrustedHTML(html) && typeof html !== 'string') {
      throw new TypeError('dangerouslySetInnerHTML.__html must be TrustedHTML or string');
    }
  }
}; โ Testing & Validation
// __tests__/trustedTypes.test.tsx
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { useTrustedHTML } from '../hooks/useTrustedTypes';
// Mock Trusted Types API for testing
beforeEach(() => {
  global.trustedTypes = {
    createPolicy: jest.fn((name, rules) => ({
      name,
      createHTML: jest.fn(rules.createHTML),
      createScript: jest.fn(rules.createScript),
      createScriptURL: jest.fn(rules.createScriptURL)
    }))
  } as any;
});
afterEach(() => {
  delete (global as any).trustedTypes;
});
describe('Trusted Types Integration', () => {
  it('should create trusted HTML content', () => {
    const TestComponent = () => {
      const trustedContent = useTrustedHTML('Test content
');
      return ;
    };
    render( ';
    const TestComponent = () => {
      const trustedContent = useTrustedHTML(maliciousHTML);
      return ;
    };
    render(
';
    const TestComponent = () => {
      const trustedContent = useTrustedHTML(maliciousHTML);
      return ;
    };
    render(Browser Console Commands
                            // Check if Trusted Types is available
                            window.trustedTypes ? 'โ
 Supported' : 'โ Not supported'
                            
                            // List all policies
                            trustedTypes.getPropertyType('innerHTML')
                            
                            // Test policy creation
                            trustedTypes.createPolicy('test', {createHTML: s => s})
                        
                    โ ๏ธ Polyfill Limitations
| Feature | Native | Polyfill | Notes | 
|---|---|---|---|
| API Surface | โ Full | โ Full | Complete API compatibility | 
| CSP Enforcement | โ Browser | โ ๏ธ Limited | Requires full polyfill version | 
| Performance | โ Native | โ ๏ธ Slower | JavaScript interception overhead | 
| DOM Sink Coverage | โ All | โ Most | Covers common sinks | 
| Default Policy | โ Yes | โ Yes | Fully supported | 
๐ก๏ธ XSS Prevention Strategies
Input Validation
- โข Validate all user input on both client and server
- โข Use allowlists for expected input patterns
- โข Reject or sanitize suspicious content
- โข Implement proper length restrictions
Output Encoding
- โข HTML entity encoding for HTML contexts
- โข JavaScript encoding for script contexts
- โข URL encoding for URL parameters
- โข CSS encoding for style contexts
Content Security Policy
- โข Implement strict CSP headers
- โข Use nonces or hashes for inline scripts
- โข Restrict script sources to trusted domains
- โข Enable Trusted Types enforcement
Framework Security
- โข Use framework's built-in XSS protection
- โข Avoid dangerous APIs (innerHTML, eval)
- โข Keep frameworks and libraries updated
- โข Use security linters and analyzers
๐ Standards & Specifications
W3C Trusted Types Specification
The official W3C specification defining the Trusted Types API for preventing DOM XSS attacks.
View W3C Specification โContent Security Policy Level 3
CSP3 specification including require-trusted-types-for directive.
View CSP3 Specification โOWASP XSS Prevention Cheat Sheet
Comprehensive guide for preventing XSS vulnerabilities in web applications.
View OWASP Guide โMDN Web Docs - Trusted Types
Developer-friendly documentation with examples and browser compatibility.
View MDN Documentation โ๐ Advanced Topics
Migration Strategies
Migrating existing applications to Trusted Types:
- โข Start with report-only mode to identify violations
- โข Create default policies for gradual migration
- โข Refactor dangerous sink usage incrementally
- โข Use automated tools to find violations
- โข Test thoroughly in staging environments
Performance Considerations
Optimizing Trusted Types implementation:
- โข Cache policy creation to avoid overhead
- โข Minimize policy complexity for better performance
- โข Use efficient sanitization libraries
- โข Profile and benchmark policy execution
- โข Consider lazy loading for non-critical policies
Browser Support & Polyfills
Current implementation status across major browsers:
| Browser | Version | Support | 
|---|---|---|
| Chrome/Edge | 83+ | โ Full | 
| Firefox | In Development | ๐ง Tracking | 
| Safari | 15.4+ | โ Full | 
| Polyfill | Available | โก Limited | 
๐ Note: Firefox implementation is actively being developed. Track progress on Bug 1508286 . Consider using feature detection and progressive enhancement for cross-browser compatibility.
Integration with Frameworks
Using Trusted Types with modern frameworks:
- โข React: Use DOMPurify with dangerouslySetInnerHTML
- โข Angular: Built-in Trusted Types support in v11+
- โข Vue: Custom directives for safe HTML binding
- โข Svelte: Compile-time XSS prevention
- โข Web Components: Shadow DOM security boundaries
๐ Privacy & Analytics
Our Commitment to Privacy
This demo uses privacy-friendly analytics to understand usage patterns and improve the educational experience. We respect your privacy and follow these principles:
- โข No personal data collection - We don't collect names, emails, or any PII
- โข IP anonymization - IP addresses are anonymized before processing
- โข No cross-site tracking - Analytics are limited to this demo only
- โข No advertising - Data is never used for advertising purposes
- โข Cookie-free option - Analytics work without storing cookies
What We Track
We collect anonymous usage data to improve the demo:
- โข Page views and navigation patterns
- โข Demo feature interactions (which examples are tested)
- โข Code copying events (to understand useful examples)
- โข Browser and device types (for compatibility)
- โข General geographic region (country level only)
Your Control
You have full control over analytics on this site. You can change your preference at any time: