Vulnerability guide

Server-side template injection vulnerability

Learn what server-side template injection is, how SSTI vulnerabilities happen in template engines, why they can lead to data exposure or remote code execution, and how to prevent them with safer template design, isolation, validation, and monitoring.

Web application securityTemplate engine securityCWE-1336Prevention guide

What server-side template injection is

Server-side template injection, often shortened to SSTI, is a vulnerability that appears when an application lets untrusted input become part of a server-side template before the template engine parses and renders it. The dangerous detail is not that the application displays user data. The dangerous detail is that the application treats user data as template syntax, expression language, helper calls, or server-side rendering instructions.

Template engines exist to combine trusted templates with changing data. A safe design keeps those two roles separate: the template is selected by the application and user-controlled values are passed as data. SSTI breaks that boundary by building the template itself from request parameters, stored fields, user-customizable content, or partially trusted admin inputs.

The risk depends on the template engine, configuration, available helpers, sandboxing, runtime permissions, and deployment model. In mild cases SSTI may only expose confusing errors or render unexpected output. In severe cases it can read sensitive server-side data, access internal objects, or become a route to remote code execution.

How SSTI works

SSTI happens in the small gap between input handling and template rendering. A value that should remain plain text is concatenated into the template string, inserted into a template expression, or accepted as an editable template from a user who should not have code-level authority. When the engine renders the result, it evaluates syntax that came from outside the trusted codebase.

The safer pattern is to load a fixed template or a carefully governed template, then pass untrusted values through the data model. The engine can still render a personalized page, email, PDF, or preview, but the user input is handled as a value rather than as instructions for the rendering engine.

Unsafe dynamic template construction
app.post('/preview', async (req, res) => {
  const template = `Hello ${req.body.displayName}, ${req.body.message}`
  const html = await templateEngine.renderString(template, accountData)

  res.send(html)
})

This pattern builds the template from request-controlled values before the template engine parses it. If those values contain template syntax that the engine understands, the server may evaluate behavior the application never intended.

Safer fixed template with data values
app.post('/preview', async (req, res) => {
  const template = await templates.load('account-preview')
  const html = await templateEngine.render(template, {
    displayName: req.body.displayName,
    message: req.body.message,
  })

  res.send(html)
})

This pattern keeps the template under application control and passes the same user values as data. The renderer can personalize the output without giving the user a chance to change the structure or logic of the template.

Visual flow

Unsafe rendering path versus safer rendering path

SSTI prevention is mostly about preserving the boundary between template code and template data. The flow below shows where that boundary is lost, and where a safer design keeps it intact.

Unsafe path
  1. 1

    Request data enters the app

    A profile name, email fragment, preview text, report title, or support macro is accepted from a user-controlled source.

  2. 2

    Input is joined to template text

    The application creates a template string by concatenating the value into markup or expression syntax before rendering.

  3. 3

    Template engine parses the result

    The engine sees one combined template and may interpret user-controlled characters as instructions instead of display text.

  4. 4

    Server-side impact becomes possible

    Depending on the engine and permissions, the issue may expose data, call helpers, read files, or reach more dangerous server-side behavior.

Safer path
  1. 1

    Application selects a trusted template

    The route chooses a known template file, governed editor template, or allow-listed template identifier.

  2. 2

    User values stay in the data model

    Display names, notes, and message fields are passed as variables rather than appended to the template source.

  3. 3

    Renderer applies limited features

    The engine runs with only the helpers, filters, and context required for that template, ideally inside a restricted environment.

  4. 4

    Output is monitored and tested

    Regression tests, template errors, suspicious rendering failures, and denied helper usage are visible to engineering and security teams.

Why SSTI matters

SSTI is high-risk because the vulnerable operation happens on the server. Unlike client-side rendering mistakes, server-side template evaluation may run near application secrets, internal services, file systems, cloud metadata, database clients, or privileged helper objects.

The impact is not identical across engines. A logic-light template engine with strict helpers and isolation has a smaller blast radius than an engine that exposes powerful language features. The safest assumption is that any user influence over template syntax deserves urgent review.

Remote code execution

Some template engines and configurations can turn SSTI into execution of server-side code or commands, especially when dangerous helpers, reflection, imports, or runtime objects are reachable.

Sensitive data exposure

A vulnerable renderer may reveal environment variables, configuration values, API keys, file contents, request context, user records, or internal object data.

Internal service access

If rendering code can reach server-side clients or URLs, the issue may become a bridge toward internal APIs, metadata endpoints, or services that are not exposed publicly.

Privilege escalation

Admin template editors, CMS theme features, support macros, or report builders may run with broader privileges than the person editing the template should have.

Availability loss

Expensive expressions, recursive templates, rendering loops, or error storms can degrade worker pools, queue systems, email jobs, document generation, and public pages.

Compliance and trust impact

Exposure of personal data, customer documents, operational secrets, or regulated records can create disclosure duties, audit findings, and long-term reputation damage.

Common forms of SSTI

SSTI is not tied to a single language or framework. It can appear anywhere user-controlled content crosses the line from data into template source. The most important classification is the context: plaintext template content, expression language context, custom template authoring, or privileged rendering features exposed to the wrong users.

FormWhat to understand
Plaintext template contextFree-form text such as greetings, previews, descriptions, or messages is appended into a template that the engine later evaluates.
Expression or variable contextA request parameter or stored field is inserted inside a template expression, variable name, helper call, filter, or conditional block.
Custom user templatesUsers, tenants, partners, or content editors can submit templates for emails, pages, reports, PDFs, notifications, invoices, or themes.
CMS and theme renderingTheme editors, content blocks, plugin systems, widget templates, and marketing pages expose powerful server-side template features.
Email and document generationPersonalized email, PDF, spreadsheet, invoice, and report generation often combines user content with templates in background workers.
Multi-tenant template featuresA SaaS product lets one tenant customize templates, but rendering occurs in shared infrastructure with broader application context.
Sandbox bypass riskA template sandbox exists, but exposed helpers, old engine versions, unsafe filters, or reachable runtime objects allow the restriction to be bypassed.

Where SSTI appears

SSTI often hides in features that look like harmless personalization. Any place that renders templates, previews user-authored content, or lets non-developers customize messages should be reviewed as carefully as a public API endpoint.

  • Email personalization, notification templates, invoice messages, receipt notes, onboarding messages, and support replies.
  • PDF, spreadsheet, export, contract, quote, report, certificate, and document generation pipelines.
  • Template previews, marketing page builders, CMS themes, widget systems, custom landing pages, and tenant branding features.
  • Support macros, help desk snippets, saved responses, workflow automations, and admin tools that render customer-controlled content.
  • Server-side rendered routes, error pages, localization strings, markdown previews, and rich text features that pass through template engines.
  • Webhook notifications, chat integrations, issue tracker comments, partner feeds, imported content, and stored data later reused in templates.
  • Legacy code paths where developers use a template engine as a string interpolation helper instead of rendering a trusted template file.

How to prevent SSTI

The durable fix is design-level separation: templates are code, user values are data. Do not concatenate untrusted input into template source, do not let ordinary users submit server-side template syntax, and do not rely on denylisting characters as the primary defense.

If your product genuinely needs user-editable templates, treat that feature as a high-risk execution surface. Limit who can edit templates, restrict the available language features, run rendering with least privilege, isolate the renderer, review templates before activation, and monitor rendering behavior.

Keep templates and data separate

Load fixed templates by trusted name and pass user-controlled values through the renderer's data object. Avoid string-building template source from requests, stored fields, or imported content.

Treat editable templates as code

Only trusted roles should edit server-side templates. Require review, version history, approvals, rollback, audit logs, and clear ownership for any template that the server will execute.

Prefer logic-light engines

Use the least powerful rendering model that satisfies the product requirement. Avoid exposing general-purpose language features when simple variable substitution is enough.

Restrict helpers and context

Pass only the data and helpers needed for the template. Remove access to request internals, environment variables, filesystem helpers, network clients, reflection, imports, and dangerous filters.

Use sandboxing as defense-in-depth

Enable the engine's restricted mode where available, but assume sandboxing can have limits. Combine it with process isolation, container hardening, read-only filesystems, and minimal runtime permissions.

Validate template identifiers

When users choose a template, allow-list the template name or ID. Do not let request parameters become filesystem paths, template source, helper names, or expression fragments.

Patch template engines and plugins

Keep template engines, CMS plugins, markdown renderers, document generators, and template extensions updated because bypasses and unsafe helpers often live in dependencies.

Log rendering failures safely

Capture template errors, denied helper calls, unusual preview failures, and high-volume render attempts without logging secrets or full sensitive documents.

Detection and response

SSTI testing should be performed only on systems you own or are explicitly authorized to test. A safe assessment focuses on whether untrusted values can influence template source or expression context, not on proving destructive server compromise.

Detection works best when code review, template inventory, dependency review, runtime telemetry, and authorized dynamic testing are combined. Scanners can help, but manual source-to-renderer review is often needed because template construction is application-specific.

  1. 1

    Inventory rendering paths

    List every place the application renders server-side templates: pages, emails, documents, previews, reports, CMS blocks, tenant customizations, workflow messages, and background jobs.

  2. 2

    Trace sources into template engines

    Review whether route parameters, request bodies, stored fields, imported content, support data, or tenant settings ever become template source, expression text, helper names, or template file paths.

  3. 3

    Review privileges and isolation

    Check which user roles can edit templates, which helpers are exposed, what data context is passed, and what filesystem, network, environment, and runtime permissions the renderer has.

  4. 4

    Use authorized testing

    Run SAST, DAST, focused manual tests, and regression checks in approved environments. Confirm that user-controlled values render as data and cannot alter template structure.

  5. 5

    Watch runtime indicators

    Monitor template syntax errors, repeated preview failures, unusual helper usage, unexpected document generation errors, spikes in render time, and denied access from sandbox or isolation controls.

  6. 6

    Contain, patch, and retest

    Remove unsafe template construction, revoke dangerous helpers, isolate rendering if needed, rotate exposed secrets when evidence supports it, add regression tests, and retest the original path.

Developer checklist

Use this checklist during code review, feature design, and remediation. It is intentionally practical: every item should map to a concrete implementation decision or test.

  • User-controlled values are passed as template data, not concatenated into template source.
  • Template names, paths, helper names, filters, and expression fragments are selected from allow-lists or trusted configuration.
  • Ordinary users cannot submit or edit server-side templates; privileged template editing has review, versioning, audit logs, and rollback.
  • The renderer receives only the minimum data context needed for the output.
  • Dangerous helpers, imports, reflection, filesystem access, network access, and environment access are disabled or unavailable to templates.
  • Rendering runs with least privilege and, for user-editable templates, inside a restricted or isolated process.
  • Template engine, CMS, markdown, document generation, and plugin dependencies are kept current.
  • Errors shown to users do not reveal engine names, versions, file paths, stack traces, secrets, or template source.
  • Logs capture rendering failures and suspicious template activity without storing sensitive rendered content.
  • Regression tests cover preview, email, document, CMS, admin, tenant customization, and stored-content rendering paths.

FAQ

What is a server-side template injection vulnerability?

SSTI is a vulnerability where untrusted input is interpreted as server-side template syntax instead of plain data. The template engine may then evaluate expressions or directives that the application did not intend to run.

Is SSTI the same as XSS?

No. XSS runs in the user's browser when unsafe content is interpreted client-side. SSTI is evaluated by the server-side template engine, which can make the impact much broader when server-side objects, files, helpers, or code execution are reachable.

What is the best first step to prevent SSTI?

Keep templates and user data separate. Load trusted templates by name and pass user-controlled values as variables. Do not build the template source by concatenating request data, stored fields, or imported content.

Are template sandboxes enough?

Sandboxing is useful defense-in-depth, but it should not be the only control. Sandboxes can be misconfigured, bypassed, or undermined by exposed helpers, old dependencies, and excessive runtime permissions.

Can products safely allow user-editable templates?

Yes, but it should be treated like a controlled code feature. Limit editing to trusted roles, reduce language power, review changes, isolate rendering, pass minimal context, log activity, and retest regularly.

References and further reading

The sources below were used to shape this guide. The wording here is original and adapted for defensive engineering, SEO clarity, and Splorix's vulnerability guide format.