Course contentsShow
← Node.js
Lesson 1815 of 1,98016. Security Hardening and Threat MitigationFree lesson

Mitigating Client-Side Execution in Node

Prevent the accidental execution of unsanitized input within template engines.

In this lesson, you will learn how to prevent attackers from injecting malicious scripts into your application by ensuring that all server-side templates treat user-provided data as plain text rather than executable code.

The Danger of Implicit Execution

When you use template engines like EJS, Pug, or Handlebars to render dynamic content, they often provide two ways to output variables: "escaped" (safe) and "unescaped" (dangerous). Vulnerabilities arise when developers accidentally use the unescaped syntax—often intended for rendering trusted HTML—to display raw user input. If an attacker submits a payload like <script>alert('XSS')</script>, an unescaped variable will cause the browser to execute that script in the context of your user’s session.

Identifying the Risk

Consider a common scenario where you display a user's profile bio. If your template engine interprets the input as raw markup, you have opened a doorway for Cross-Site Scripting (XSS).

In EJS, for example:

// DANGEROUS: The '-' tag renders raw, unsanitized HTML
<p>User Bio: <%- userBio %></p>

// SAFE: The '=' tag automatically escapes HTML entities
<p>User Bio: <%= userBio %></p>

When using <%= %>, the engine transforms special characters like < and > into their HTML entity equivalents (&lt; and &gt;). This ensures the browser displays the literal text instead of interpreting it as a script tag.

Defensive Strategies

  1. Default to Escaping: Always prefer the auto-escaping output syntax provided by your template engine. Avoid "unescaped" or "raw" output flags unless you are rendering trusted, pre-sanitized HTML from your own database.
  2. Sanitize Aggressively: If you absolutely must render user-provided HTML, run the input through a battle-tested library like dompurify (often used with jsdom) before it ever reaches the template engine.
  3. Context-Aware Encoding: Understand that different contexts (e.g., inside a <script> tag versus inside a <div>) require different escaping rules. Standard HTML escaping is insufficient if you are injecting variables directly into a JavaScript block. Always avoid embedding server-side variables directly into client-side script tags.

By treating all user input as untrusted strings by default, you eliminate the risk of the template engine inadvertently executing malicious payloads.

Key Takeaway: Never use "raw" or "unescaped" template tags for user-supplied data; always default to HTML-encoded output to treat dynamic input as literal text rather than executable markup.