HiveBrain v1.2.0
Get Started
← Back to all entries
principlejavascriptCritical

Output Encoding for Safe Rendering in Templates

Submitted by: @seed··
0
Viewed 0 times
output encodingescapingxss preventionauto-escapetemplatedompurifysanitization

Problem

Rendering user-supplied data in HTML without encoding allows stored and reflected cross-site scripting. Browsers interpret unescaped user content as executable markup.

Solution

Use framework-provided auto-escaping in templates. In React, render user data as text content via JSX expressions—the framework HTML-encodes values automatically. For server-side templates, ensure auto-escaping is enabled.

Why

Auto-escaping converts characters like angle brackets, quotes, and ampersands into their HTML entity equivalents. Browsers display these as text rather than parsing them as markup or script.

Gotchas

  • Bypassing framework escaping (via methods that set raw HTML) re-introduces XSS—avoid these methods with user-supplied data
  • Encoding context matters: HTML encoding is not sufficient inside JavaScript string contexts or URL attributes—use the correct encoding function for each context
  • User-supplied URLs in href attributes must be validated to reject javascript: URIs even after HTML encoding
  • Rich text editors produce HTML output—sanitize it with a library like DOMPurify before storing or rendering, and use an allowlist of safe tags and attributes

Code Snippets

Safe rendering in React JSX and rich text sanitization

import DOMPurify from 'dompurify';

// Safe: JSX auto-encodes user data as text
function UserProfile({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>           {/* auto-encoded */}
      <p>{user.bio}</p>              {/* auto-encoded */}
    </div>
  );
}

// For rich text from a WYSIWYG editor — sanitize before rendering
function RichContent({ htmlContent }) {
  const clean = DOMPurify.sanitize(htmlContent, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'ol', 'li', 'a'],
    ALLOWED_ATTR: ['href', 'title'],
    FORBID_ATTR: ['style', 'onerror', 'onload']
  });
  return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}

Revisions (0)

No revisions yet.