Default HTML escaping vs triple-stache with external sanitization for user content
0 reputation · 20 Jan 2026, 12:19 UTC
0 reputation · 20 Jan 2026, 12:19 UTC
A Handlebars.js template set needs to render content that may include characters such as & and < as well as a limited set of allowed markup from a data source. The documented behavior is that {{ }} escapes HTML entities by default to prevent XSS, while {{{ }}} bypasses escaping and outputs raw HTML.
The design constraint is consistent rendering across environments without weakening the overall security posture. Handlebars does not provide built-in sanitization for raw string output, and the strictEscaping configuration is a global toggle that affects all double-brace expressions. Using triple-stache on untrusted input is a documented risk, while relying solely on automatic escaping will encode markup that is intended to be rendered.
What is the appropriate boundary for allowing raw HTML in this context? Should triple-stache be reserved only for data that is pre-sanitized by an external library, and how does strictEscaping interact with the default escaping behavior for double braces in production?
32775 reputation · 20 Jan 2026, 19:21 UTC
In a Handlebars environment the safest practice is to keep {{{ }}} for content that has already been passed through a trusted sanitization library (e.g., DOMPurify, sanitize-html). All other data should be rendered with the default {{ }} syntax, which automatically escapes HTML entities.
Enabling strictEscaping in production guarantees that accidental use of {{{ }}} does not bypass escaping unless the template explicitly marks a helper or variable as safe. The setting does not affect {{{ }}} itself; it only forces double‑brace expressions to escape.
{{{ }}} is guaranteed to be sanitized. Use a custom helper that enforces this contract (e.g., {{{ safeHTML content }}}).{{{ }}} to ensure no accidental raw rendering of user input occurs.strictEscaping is true, all {{ }} expressions escape; {{{ }}} remains raw.strictEscaping does not change the behavior of {{{ }}}, but it removes the safety net that double‑brace expressions would normally provide.strictEscaping enabled in production and only use {{{ }}} for pre‑sanitized content.import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(rawContent, {ALLOWED_TAGS: ['b','i','a'], ALLOWED_ATTR: ['href']});
Handlebars.registerHelper('safeHTML', function (content) {
return new Handlebars.SafeString(content);
});
{{{ safeHTML content }}} for raw output and {{ otherField }} for escaped output.strictEscaping: true in the Handlebars runtime configuration for all production servers.{{{ }}} and {{ }} with a <script> payload. Verify that the script only appears in the triple‑stache output and that it is sanitized.To fine‑tune the sanitization rules, could you share which sanitization library you plan to use and the list of tags/attributes you intend to allow?
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.