or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bootstrap-platform.mddocument-management.mdevent-management.mdhydration.mdindex.mdsecurity-sanitization.mdtesting-debug.md
tile.json

security-sanitization.mddocs/

Security and Sanitization

DOM sanitization services for preventing Cross Site Scripting (XSS) attacks, with safe value types and bypass methods for trusted content. Essential for handling user-generated content and dynamic HTML.

Capabilities

DOM Sanitizer

Abstract service that provides sanitization for different security contexts and bypass methods for trusted content.

/**
 * DomSanitizer helps preventing Cross Site Scripting Security bugs (XSS) by sanitizing
 * values to be safe to use in the different DOM contexts.
 */
abstract class DomSanitizer implements Sanitizer {
  /**
   * Gets a safe value from either a known safe value or a value with unknown safety.
   * If the given value is already a SafeValue, this method returns the unwrapped value.
   * If the security context is HTML and the given value is a plain string, this method
   * sanitizes the string, removing any potentially unsafe content.
   * @param context - The security context in which the value will be used
   * @param value - The value to sanitize
   * @returns Sanitized string value or null
   */
  abstract sanitize(context: SecurityContext, value: SafeValue | string | null): string | null;

  /**
   * Bypass security and trust the given value to be safe HTML.
   * WARNING: calling this method with untrusted user data exposes your application to XSS security risks!
   * @param value - The HTML string to trust
   * @returns SafeHtml value that bypasses sanitization
   */
  abstract bypassSecurityTrustHtml(value: string): SafeHtml;

  /**
   * Bypass security and trust the given value to be safe style value (CSS).
   * WARNING: calling this method with untrusted user data exposes your application to XSS security risks!
   * @param value - The CSS string to trust
   * @returns SafeStyle value that bypasses sanitization
   */
  abstract bypassSecurityTrustStyle(value: string): SafeStyle;

  /**
   * Bypass security and trust the given value to be safe JavaScript.
   * WARNING: calling this method with untrusted user data exposes your application to XSS security risks!
   * @param value - The JavaScript string to trust
   * @returns SafeScript value that bypasses sanitization
   */
  abstract bypassSecurityTrustScript(value: string): SafeScript;

  /**
   * Bypass security and trust the given value to be a safe style URL.
   * WARNING: calling this method with untrusted user data exposes your application to XSS security risks!
   * @param value - The URL string to trust
   * @returns SafeUrl value that bypasses sanitization
   */
  abstract bypassSecurityTrustUrl(value: string): SafeUrl;

  /**
   * Bypass security and trust the given value to be a safe resource URL.
   * WARNING: calling this method with untrusted user data exposes your application to XSS security risks!
   * @param value - The resource URL string to trust
   * @returns SafeResourceUrl value that bypasses sanitization
   */
  abstract bypassSecurityTrustResourceUrl(value: string): SafeResourceUrl;
}

Usage Examples:

import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
import { Component } from "@angular/core";

@Component({
  selector: 'app-content',
  template: `
    <div [innerHTML]="sanitizedHtml"></div>
    <div [style.background-image]="trustedUrl"></div>
  `
})
export class ContentComponent {
  sanitizedHtml: SafeHtml;
  trustedUrl: SafeStyle;

  constructor(private sanitizer: DomSanitizer) {
    // Sanitize user-provided HTML
    const userHtml = '<script>alert("xss")</script><p>Safe content</p>';
    this.sanitizedHtml = this.sanitizer.sanitize(SecurityContext.HTML, userHtml);

    // Trust a known safe URL
    const imageUrl = 'url(https://trusted-cdn.com/image.jpg)';
    this.trustedUrl = this.sanitizer.bypassSecurityTrustStyle(imageUrl);
  }

  // Method to safely set dynamic HTML
  setSafeHtml(html: string): SafeHtml {
    // Only bypass security for content you trust completely
    if (this.isContentTrusted(html)) {
      return this.sanitizer.bypassSecurityTrustHtml(html);
    }
    
    // Let Angular sanitize untrusted content
    return this.sanitizer.sanitize(SecurityContext.HTML, html);
  }

  private isContentTrusted(html: string): boolean {
    // Implement your trust validation logic
    return html.startsWith('<p>') && !html.includes('<script>');
  }
}

Safe Value Types

Marker interfaces that indicate values have been validated as safe for specific security contexts.

/**
 * Marker interface for a value that's safe to use in a particular context.
 */
interface SafeValue {}

/**
 * Marker interface for a value that's safe to use as HTML.
 */
interface SafeHtml extends SafeValue {}

/**
 * Marker interface for a value that's safe to use as style (CSS).
 */
interface SafeStyle extends SafeValue {}

/**
 * Marker interface for a value that's safe to use as JavaScript.
 */
interface SafeScript extends SafeValue {}

/**
 * Marker interface for a value that's safe to use as a URL linking to a document.
 */
interface SafeUrl extends SafeValue {}

/**
 * Marker interface for a value that's safe to use as a URL to load executable code from.
 */
interface SafeResourceUrl extends SafeValue {}

Usage Examples:

import { DomSanitizer, SafeHtml, SafeUrl } from "@angular/platform-browser";

@Injectable()
export class SafeContentService {
  constructor(private sanitizer: DomSanitizer) {}

  // Create safe HTML for trusted templates
  createSafeHtml(template: string, data: any): SafeHtml {
    const processedTemplate = this.processTemplate(template, data);
    return this.sanitizer.bypassSecurityTrustHtml(processedTemplate);
  }

  // Create safe URLs for trusted sources
  createSafeUrl(url: string): SafeUrl {
    if (this.isUrlTrusted(url)) {
      return this.sanitizer.bypassSecurityTrustUrl(url);
    }
    throw new Error('Untrusted URL');
  }

  private isUrlTrusted(url: string): boolean {
    const trustedDomains = ['https://api.myapp.com', 'https://cdn.myapp.com'];
    return trustedDomains.some(domain => url.startsWith(domain));
  }

  private processTemplate(template: string, data: any): string {
    // Process template with trusted data
    return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
      return data[key] || '';
    });
  }
}

Security Contexts

Security contexts define how values are validated and sanitized based on their intended use.

/**
 * Security context in which to sanitize a value.
 * Defines how Angular should sanitize values in different DOM contexts.
 */
enum SecurityContext {
  NONE = 0,
  HTML = 1,
  STYLE = 2,
  SCRIPT = 3,
  URL = 4,
  RESOURCE_URL = 5
}

Security Context Usage:

import { SecurityContext, DomSanitizer } from "@angular/platform-browser";

@Injectable()
export class SecurityService {
  constructor(private sanitizer: DomSanitizer) {}

  sanitizeForContext(value: string, context: SecurityContext): string | null {
    switch (context) {
      case SecurityContext.HTML:
        // Removes script tags, javascript: URLs, etc.
        return this.sanitizer.sanitize(SecurityContext.HTML, value);
      
      case SecurityContext.STYLE:
        // Validates CSS values
        return this.sanitizer.sanitize(SecurityContext.STYLE, value);
      
      case SecurityContext.URL:
        // Validates URLs, blocks javascript: URLs
        return this.sanitizer.sanitize(SecurityContext.URL, value);
      
      case SecurityContext.SCRIPT:
        // Always throws error - scripts cannot be sanitized
        return this.sanitizer.sanitize(SecurityContext.SCRIPT, value);
      
      case SecurityContext.RESOURCE_URL:
        // Always throws error for untrusted resource URLs
        return this.sanitizer.sanitize(SecurityContext.RESOURCE_URL, value);
      
      default:
        return value;
    }
  }
}

Best Practices:

// ❌ DON'T: Bypass security for user input
const userInput = getUserInput();
const dangerousHtml = sanitizer.bypassSecurityTrustHtml(userInput);

// ✅ DO: Sanitize user input
const userInput = getUserInput();
const safeHtml = sanitizer.sanitize(SecurityContext.HTML, userInput);

// ✅ DO: Only bypass for content you control
const trustedTemplate = '<div class="highlight">{{content}}</div>';
const safeTemplate = sanitizer.bypassSecurityTrustHtml(trustedTemplate);

// ✅ DO: Validate before bypassing
const url = getImageUrl();
if (url.startsWith('https://trusted-cdn.com/')) {
  const safeUrl = sanitizer.bypassSecurityTrustUrl(url);
}